Perfprofd: Add a symbolizer based on simpleperf code
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
diff --git a/perfprofd/Android.bp b/perfprofd/Android.bp
index 893991e..8229cd9 100644
--- a/perfprofd/Android.bp
+++ b/perfprofd/Android.bp
@@ -9,6 +9,58 @@
]
//
+// 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 @@
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 @@
"configreader.cc",
"cpuconfig.cc",
"perfprofdcore.cc",
+ "symbolizer.cc"
],
cflags: perfprofd_cflags,
@@ -85,6 +141,7 @@
"libperfprofdcore",
"libperfprofdutils",
"libperfprofd_binder",
+ "libperfprofd_elf_read",
],
shared_libs: [
"liblog",
diff --git a/perfprofd/config.h b/perfprofd/config.h
index 219db06..bbbcb3f 100644
--- a/perfprofd/config.h
+++ b/perfprofd/config.h
@@ -90,6 +90,9 @@
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;
diff --git a/perfprofd/perfprofdcore.cc b/perfprofd/perfprofdcore.cc
index 30c1216..4cbf813 100644
--- a/perfprofd/perfprofdcore.cc
+++ b/perfprofd/perfprofdcore.cc
@@ -28,11 +28,13 @@
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
-#include <string>
-#include <sstream>
-#include <map>
-#include <set>
+
#include <cctype>
+#include <map>
+#include <memory>
+#include <set>
+#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 @@
//
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
index 0000000..9878956
--- /dev/null
+++ b/perfprofd/simpleperf
@@ -0,0 +1 @@
+../simpleperf
\ No newline at end of file
diff --git a/perfprofd/symbolizer.cc b/perfprofd/symbolizer.cc
new file mode 100644
index 0000000..3f7ea4d
--- /dev/null
+++ b/perfprofd/symbolizer.cc
@@ -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
+
diff --git a/perfprofd/symbolizer.h b/perfprofd/symbolizer.h
index 68551d3..87e8a25 100644
--- a/perfprofd/symbolizer.h
+++ b/perfprofd/symbolizer.h
@@ -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 @@
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_
diff --git a/perfprofd/tests/Android.bp b/perfprofd/tests/Android.bp
index 1e4ea3d..c173805 100644
--- a/perfprofd/tests/Android.bp
+++ b/perfprofd/tests/Android.bp
@@ -33,6 +33,7 @@
static_libs: [
"libperfprofdcore",
"libperfprofdmockutils",
+ "libperfprofd_elf_read",
"libbase",
],
shared_libs: [