diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2020-08-27 19:54:44 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-08-27 19:54:44 +0000 |
commit | 3b2fa33a196f41991f55f2f54e0a2de704e1e734 (patch) | |
tree | 453a6513547cb9eb5d3d428fdb91ab737c63ea74 | |
parent | 416ff0a479ba926c72bc19a393ca14f3e8ead909 (diff) | |
parent | fc7c7d73f38d2008ef4e7a0ef63aaa33a905a3d3 (diff) | |
download | extras-3b2fa33a196f41991f55f2f54e0a2de704e1e734.tar.gz |
Merge "simpleperf: add perf symbol map dso + test" am: fc7c7d73f3
Original change: https://android-review.googlesource.com/c/platform/system/extras/+/1413508
Change-Id: I0a99dd584acc4bd34689e16f1f6d37f244c50d8c
-rw-r--r-- | simpleperf/dso.cpp | 14 | ||||
-rw-r--r-- | simpleperf/dso.h | 1 | ||||
-rw-r--r-- | simpleperf/dso_test.cpp | 8 | ||||
-rw-r--r-- | simpleperf/thread_tree.cpp | 51 | ||||
-rw-r--r-- | simpleperf/thread_tree.h | 8 | ||||
-rw-r--r-- | simpleperf/thread_tree_test.cpp | 22 | ||||
-rw-r--r-- | simpleperf/utils.h | 6 |
7 files changed, 109 insertions, 1 deletions
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp index f4239a60..efe65721 100644 --- a/simpleperf/dso.cpp +++ b/simpleperf/dso.cpp @@ -691,6 +691,16 @@ class KernelModuleDso : public Dso { } }; +class SymbolMapFileDso : public Dso { + public: + SymbolMapFileDso(const std::string& path) : Dso(DSO_SYMBOL_MAP_FILE, path, path) {} + + uint64_t IpToVaddrInFile(uint64_t ip, uint64_t, uint64_t) override { return ip; } + + protected: + std::vector<Symbol> LoadSymbols() override { return {}; } +}; + class UnknownDso : public Dso { public: UnknownDso(const std::string& path) : Dso(DSO_UNKNOWN_FILE, path, path) {} @@ -722,6 +732,8 @@ std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type, const std::string& dso_pat } case DSO_DEX_FILE: return std::unique_ptr<Dso>(new DexFileDso(dso_path, dso_path)); + case DSO_SYMBOL_MAP_FILE: + return std::unique_ptr<Dso>(new SymbolMapFileDso(dso_path)); case DSO_UNKNOWN_FILE: return std::unique_ptr<Dso>(new UnknownDso(dso_path)); default: @@ -745,6 +757,8 @@ const char* DsoTypeToString(DsoType dso_type) { return "dso_elf_file"; case DSO_DEX_FILE: return "dso_dex_file"; + case DSO_SYMBOL_MAP_FILE: + return "dso_symbol_map_file"; default: return "unknown"; } diff --git a/simpleperf/dso.h b/simpleperf/dso.h index 6afeff41..aa7ca048 100644 --- a/simpleperf/dso.h +++ b/simpleperf/dso.h @@ -106,6 +106,7 @@ enum DsoType { DSO_KERNEL_MODULE, DSO_ELF_FILE, DSO_DEX_FILE, // For files containing dex files, like .vdex files. + DSO_SYMBOL_MAP_FILE, DSO_UNKNOWN_FILE, }; diff --git a/simpleperf/dso_test.cpp b/simpleperf/dso_test.cpp index 5d405622..566d76b9 100644 --- a/simpleperf/dso_test.cpp +++ b/simpleperf/dso_test.cpp @@ -219,3 +219,11 @@ TEST(dso, kernel_module) { std::unique_ptr<Dso> dso = Dso::CreateDso(DSO_KERNEL_MODULE, ELF_FILE, false); ASSERT_EQ(dso->GetDebugFilePath(), GetTestData(ELF_FILE)); } + +TEST(dso, symbol_map_file) { + auto dso = Dso::CreateDso(DSO_SYMBOL_MAP_FILE, "perf-123.map"); + ASSERT_TRUE(dso); + ASSERT_EQ(DSO_SYMBOL_MAP_FILE, dso->type()); + ASSERT_EQ(0x12345678, dso->IpToVaddrInFile(0x12345678, 0x0, 0x0)); + ASSERT_EQ(0x12345678, dso->IpToVaddrInFile(0x12345678, 0xe9201000, 0xa5000)); +} diff --git a/simpleperf/thread_tree.cpp b/simpleperf/thread_tree.cpp index 6babf8cc..10cc018b 100644 --- a/simpleperf/thread_tree.cpp +++ b/simpleperf/thread_tree.cpp @@ -25,6 +25,7 @@ #include "perf_event.h" #include "record.h" +#include "utils.h" namespace simpleperf { @@ -131,6 +132,35 @@ void ThreadTree::AddThreadMap(int pid, int tid, uint64_t start_addr, uint64_t le InsertMap(*thread->maps, MapEntry(start_addr, len, pgoff, dso, false, flags)); } +void ThreadTree::AddThreadMapsForDsoSymbols(ThreadEntry* thread, Dso* dso) { + const uint64_t page_size = GetPageSize(); + + auto maps = thread->maps; + + uint64_t map_start = 0; + uint64_t map_end = 0; + + // Dso symbols are sorted by address. Walk and calculate containing pages. + for (const auto& sym : dso->GetSymbols()) { + uint64_t sym_map_start = AlignDown(sym.addr, page_size); + uint64_t sym_map_end = Align(sym.addr + sym.len, page_size); + + if (map_end < sym_map_start) { + if (map_start < map_end) { + InsertMap(*maps, MapEntry(map_start, map_end - map_start, map_start, dso, false, 0)); + } + map_start = sym_map_start; + } + if (map_end < sym_map_end) { + map_end = sym_map_end; + } + } + + if (map_start < map_end) { + InsertMap(*maps, MapEntry(map_start, map_end - map_start, map_start, dso, false, 0)); + } +} + Dso* ThreadTree::FindUserDsoOrNew(const std::string& filename, uint64_t start_addr, DsoType dso_type) { auto it = user_dso_tree_.find(filename); @@ -144,6 +174,27 @@ Dso* ThreadTree::FindUserDsoOrNew(const std::string& filename, uint64_t start_ad return it->second.get(); } +namespace { + +// Real map file path depends on where the process can create files. +// For example, app can create files only in its data directory. +// Use normalized name inherited from pid instead. +std::string GetSymbolMapDsoName(int pid) { + return android::base::StringPrintf("perf-%d.map", pid); +} + +} // namespace + +void ThreadTree::AddSymbolsForProcess(int pid, std::vector<Symbol>* symbols) { + auto name = GetSymbolMapDsoName(pid); + + auto dso = FindUserDsoOrNew(name, 0, DSO_SYMBOL_MAP_FILE); + dso->SetSymbols(symbols); + + auto thread = FindThreadOrNew(pid, pid); + AddThreadMapsForDsoSymbols(thread, dso); +} + const MapEntry* ThreadTree::AllocateMap(const MapEntry& entry) { map_storage_.emplace_back(new MapEntry(entry)); return map_storage_.back().get(); diff --git a/simpleperf/thread_tree.h b/simpleperf/thread_tree.h index 76d3403d..a90c4951 100644 --- a/simpleperf/thread_tree.h +++ b/simpleperf/thread_tree.h @@ -113,6 +113,11 @@ class ThreadTree { const MapSet& GetKernelMaps() { return kernel_maps_; } void AddThreadMap(int pid, int tid, uint64_t start_addr, uint64_t len, uint64_t pgoff, const std::string& filename, uint32_t flags = 0); + + // Add process symbols that do not correspond to any real dso. + // For example, these might be symbols generated by a JIT. + void AddSymbolsForProcess(int pid, std::vector<Symbol>* symbols); + const MapEntry* FindMap(const ThreadEntry* thread, uint64_t ip, bool in_kernel); // Find map for an ip address when we don't know whether it is in kernel. @@ -150,6 +155,9 @@ class ThreadTree { const MapEntry* AllocateMap(const MapEntry& entry); void InsertMap(MapSet& maps, const MapEntry& entry); + // Add thread maps to cover symbols in dso. + void AddThreadMapsForDsoSymbols(ThreadEntry* thread, Dso* dso); + std::unordered_map<int, std::unique_ptr<ThreadEntry>> thread_tree_; std::vector<std::unique_ptr<std::string>> thread_comm_storage_; diff --git a/simpleperf/thread_tree_test.cpp b/simpleperf/thread_tree_test.cpp index d00ebcb9..c75e98c4 100644 --- a/simpleperf/thread_tree_test.cpp +++ b/simpleperf/thread_tree_test.cpp @@ -18,6 +18,8 @@ #include <gtest/gtest.h> +#include "read_symbol_map.h" + using namespace simpleperf; class ThreadTreeTest : public ::testing::Test { @@ -64,6 +66,12 @@ class ThreadTreeTest : public ::testing::Test { } } + const Symbol* FindSymbol(int pid, int tid, uint64_t ip, bool in_kernel = false) { + auto thread = thread_tree_.FindThreadOrNew(pid, tid); + auto map = thread_tree_.FindMap(thread, ip, in_kernel); + return thread_tree_.FindSymbol(map, ip, nullptr, nullptr); + } + std::vector<std::string> expected_names_; ThreadTree thread_tree_; }; @@ -120,3 +128,17 @@ TEST_F(ThreadTreeTest, reused_tid_without_thread_exit) { thread_tree_.ForkThread(1, 2, 1, 1); thread_tree_.ForkThread(2, 2, 1, 1); } + +TEST_F(ThreadTreeTest, add_symbols_for_process) { + std::string symbol_map("0x2000 0x20 two\n" + "0x1000 0x10 one\n" + "0x3000 0x30 three\n"); + + auto symbols = ReadSymbolMapFromString(symbol_map); + + thread_tree_.AddSymbolsForProcess(1, &symbols); + + ASSERT_STREQ("one", FindSymbol(1, 1, 0x1000)->Name()); + ASSERT_STREQ("two", FindSymbol(1, 1, 0x2010)->Name()); + ASSERT_STREQ("three", FindSymbol(1, 1, 0x302f)->Name()); +} diff --git a/simpleperf/utils.h b/simpleperf/utils.h index 6bb51d3c..db00d23a 100644 --- a/simpleperf/utils.h +++ b/simpleperf/utils.h @@ -30,8 +30,12 @@ #include <android-base/unique_fd.h> #include <ziparchive/zip_archive.h> +static inline uint64_t AlignDown(uint64_t value, uint64_t alignment) { + return value & ~(alignment - 1); +} + static inline uint64_t Align(uint64_t value, uint64_t alignment) { - return (value + alignment - 1) & ~(alignment - 1); + return AlignDown(value + alignment - 1, alignment); } #ifdef _WIN32 |