OSDN Git Service

Perfprofd: Add a symbolizer based on simpleperf code
authorAndreas Gampe <agampe@google.com>
Mon, 8 Jan 2018 20:39:38 +0000 (12:39 -0800)
committerAndreas Gampe <agampe@google.com>
Tue, 9 Jan 2018 20:59:31 +0000 (12:59 -0800)
For the time being, compile a small library straight out of
simpleperf sources. Once simpleperf has been transitioned to
Soong, use it directly.

Test: m
Change-Id: I2aa4695fda97ce424b9e9382db4346b8b0e38d2a

perfprofd/Android.bp
perfprofd/config.h
perfprofd/perfprofdcore.cc
perfprofd/simpleperf [new symlink]
perfprofd/symbolizer.cc [new file with mode: 0644]
perfprofd/symbolizer.h
perfprofd/tests/Android.bp

index 893991e..8229cd9 100644 (file)
@@ -9,6 +9,58 @@ perfprofd_cppflags = [
 ]
 
 //
+// Static library for ELF symbolization.
+//
+// TODO: make this a proper part of simpleperf once that is moved to Soong.
+//
+
+cc_library_static {
+    name: "libperfprofd_elf_read",
+
+    export_include_dirs: [
+        "simpleperf",
+    ],
+
+    cflags: [
+        "-DSIMPLEPERF_REVISION=\"dummy\"",
+    ],
+
+    static_libs: [
+        "libbase",
+    ],
+    // Use whole-static to avoid having to pull this in later.
+    whole_static_libs: [
+        "libLLVMObject",
+        "libLLVMBitReader",
+        "libLLVMMC",
+        "libLLVMMCParser",
+        "libLLVMCore",
+        "libLLVMSupport",
+        "liblog",
+        "liblzma",
+        "libz",
+        "libziparchive",
+    ],
+
+    target: {
+        // Required for LLVM.
+        linux_glibc: {
+            host_ldlibs: [
+                "-lncurses",
+            ],
+        },
+    },
+
+    srcs: [
+        "simpleperf/read_apk.cpp",
+        "simpleperf/read_elf.cpp",
+        "simpleperf/utils.cpp",
+    ],
+
+    group_static_libs: true,
+}
+
+//
 // Static library containing guts of AWP daemon.
 //
 
@@ -17,7 +69,10 @@ cc_library_static {
 
     local_include_dirs: ["quipper/kernel-headers"],
     export_include_dirs: ["."],
-    static_libs: ["libbase"],
+    static_libs: [
+        "libbase",
+        "libperfprofd_elf_read",
+    ],
     srcs: [
         "perf_profile.proto",
         "quipper/perf_utils.cc",
@@ -29,6 +84,7 @@ cc_library_static {
         "configreader.cc",
         "cpuconfig.cc",
         "perfprofdcore.cc",
+        "symbolizer.cc"
     ],
 
     cflags: perfprofd_cflags,
@@ -85,6 +141,7 @@ cc_binary {
         "libperfprofdcore",
         "libperfprofdutils",
         "libperfprofd_binder",
+        "libperfprofd_elf_read",
     ],
     shared_libs: [
         "liblog",
index 219db06..bbbcb3f 100644 (file)
@@ -90,6 +90,9 @@ struct Config {
   bool collect_booting = true;
   bool collect_camera_active = false;
 
+  // If true, use an ELF symbolizer to on-device symbolize.
+  bool use_elf_symbolizer = true;
+
   // Sleep for the given number of seconds.
   virtual void Sleep(size_t seconds) = 0;
 
index 30c1216..4cbf813 100644 (file)
 #include <sys/wait.h>
 #include <time.h>
 #include <unistd.h>
-#include <string>
-#include <sstream>
+
+#include <cctype>
 #include <map>
+#include <memory>
 #include <set>
-#include <cctype>
+#include <sstream>
+#include <string>
 
 #include <android-base/file.h>
 #include <android-base/macros.h>
@@ -44,6 +46,7 @@
 #include "perf_data_converter.h"
 #include "cpuconfig.h"
 #include "configreader.h"
+#include "symbolizer.h"
 
 //
 // Perf profiling daemon -- collects system-wide profiles using
@@ -801,7 +804,11 @@ static PROFILE_RESULT collect_profile(Config& config, int seq)
   //
   std::string path = android::base::StringPrintf(
       "%s.encoded.%d", data_file_path.c_str(), seq);
-  return encode_to_proto(data_file_path, path.c_str(), config, cpu_utilization, nullptr);
+  std::unique_ptr<perfprofd::Symbolizer> symbolizer;
+  if (config.use_elf_symbolizer) {
+    symbolizer = perfprofd::CreateELFSymbolizer();
+  }
+  return encode_to_proto(data_file_path, path.c_str(), config, cpu_utilization, symbolizer.get());
 }
 
 //
diff --git a/perfprofd/simpleperf b/perfprofd/simpleperf
new file mode 120000 (symlink)
index 0000000..9878956
--- /dev/null
@@ -0,0 +1 @@
+../simpleperf
\ No newline at end of file
diff --git a/perfprofd/symbolizer.cc b/perfprofd/symbolizer.cc
new file mode 100644 (file)
index 0000000..3f7ea4d
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "symbolizer.h"
+
+#include <map>
+#include <memory>
+#include <unordered_map>
+
+#include <android-base/logging.h>
+
+#include "build_id.h"
+#include "read_elf.h"
+
+namespace perfprofd {
+
+namespace {
+
+struct SimpleperfSymbolizer : public Symbolizer {
+  // For simplicity, we assume non-overlapping symbols.
+  struct Symbol {
+    std::string name;
+    uint64_t length;
+  };
+  using SymbolMap = std::map<uint64_t, Symbol>;
+
+  std::string Decode(const std::string& dso, uint64_t address) override {
+    auto it = dsos.find(dso);
+    if (it == dsos.end()) {
+      LoadDso(dso);
+      it = dsos.find(dso);
+      DCHECK(it != dsos.end());
+    }
+
+    const SymbolMap& map = it->second;
+    if (map.empty()) {
+      return "";
+    }
+    auto upper_bound = map.upper_bound(address);
+    if (upper_bound == map.begin()) {
+      // Nope, not in the map.
+      return "";
+    }
+
+    upper_bound--;
+    if (upper_bound->first + upper_bound->second.length > address) {
+      // This element covers the given address, return its name.
+      return upper_bound->second.name;
+    }
+
+    return "";
+  }
+
+  void LoadDso(const std::string& dso) {
+    SymbolMap data;
+    auto callback = [&data](const ElfFileSymbol& sym) {
+      Symbol symbol;
+      symbol.name = sym.name;
+      symbol.length = sym.len;
+      data.emplace(sym.vaddr, std::move(symbol));
+    };
+    ElfStatus status = ParseSymbolsFromElfFile(dso, BuildId(), callback);
+    if (status != ElfStatus::NO_ERROR) {
+      LOG(WARNING) << "Could not parse dso " << dso << ": " << status;
+    }
+    dsos.emplace(dso, std::move(data));
+  }
+
+  std::unordered_map<std::string, SymbolMap> dsos;
+};
+
+}  // namespace
+
+std::unique_ptr<Symbolizer> CreateELFSymbolizer() {
+  return std::unique_ptr<Symbolizer>(new SimpleperfSymbolizer());
+}
+
+}  // namespace perfprofd
+
index 68551d3..87e8a25 100644 (file)
@@ -18,6 +18,8 @@
 #ifndef SYSTEM_EXTRAS_PERFPROFD_SYMBOLIZER_H_
 #define SYSTEM_EXTRAS_PERFPROFD_SYMBOLIZER_H_
 
+#include <memory>
+
 namespace perfprofd {
 
 struct Symbolizer {
@@ -25,6 +27,8 @@ struct Symbolizer {
   virtual std::string Decode(const std::string& dso, uint64_t address) = 0;
 };
 
+std::unique_ptr<Symbolizer> CreateELFSymbolizer();
+
 }  // namespace perfprofd
 
 #endif  // SYSTEM_EXTRAS_PERFPROFD_SYMBOLIZER_H_
index 1e4ea3d..c173805 100644 (file)
@@ -33,6 +33,7 @@ cc_test {
     static_libs: [
         "libperfprofdcore",
         "libperfprofdmockutils",
+        "libperfprofd_elf_read",
         "libbase",
     ],
     shared_libs: [