diff options
author | David Srbecky <dsrbecky@google.com> | 2018-02-23 19:25:02 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2018-02-23 19:25:02 +0000 |
commit | e92a2d8a4329f9d91777a81db667ef71114b5ca6 (patch) | |
tree | c177e6b666f10d9946e5f1f33e727020ac67d186 | |
parent | 6e7c4df7cc2374ba72996953c74541b5a0aa7a63 (diff) | |
parent | 15933b6e39d1afbda8538a42ae206286582e54cc (diff) | |
download | extras-e92a2d8a4329f9d91777a81db667ef71114b5ca6.tar.gz |
Merge "Create maps for libunwind only if they changed."
-rw-r--r-- | simpleperf/OfflineUnwinder.cpp | 61 | ||||
-rw-r--r-- | simpleperf/OfflineUnwinder.h | 12 | ||||
-rw-r--r-- | simpleperf/thread_tree.cpp | 19 | ||||
-rw-r--r-- | simpleperf/thread_tree.h | 5 |
4 files changed, 62 insertions, 35 deletions
diff --git a/simpleperf/OfflineUnwinder.cpp b/simpleperf/OfflineUnwinder.cpp index eb557186..ae33cafd 100644 --- a/simpleperf/OfflineUnwinder.cpp +++ b/simpleperf/OfflineUnwinder.cpp @@ -18,6 +18,7 @@ #include <android-base/logging.h> #include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> #include <unwindstack/MachineArm.h> #include <unwindstack/MachineArm64.h> #include <unwindstack/MachineX86.h> @@ -126,29 +127,42 @@ bool OfflineUnwinder::UnwindCallChain(const ThreadEntry& thread, const RegSet& r } uint64_t stack_addr = sp_reg_value; - std::vector<backtrace_map_t> bt_maps(thread.maps->size()); - size_t map_index = 0; - for (auto& map : *thread.maps) { - backtrace_map_t& bt_map = bt_maps[map_index++]; - bt_map.start = map->start_addr; - bt_map.end = map->start_addr + map->len; - bt_map.offset = map->pgoff; - bt_map.name = map->dso->GetDebugFilePath(); - if (bt_map.offset == 0) { - size_t apk_pos = bt_map.name.find_last_of('!'); - if (apk_pos != std::string::npos) { - // The unwinder does not understand the ! format, so change back to - // the previous format (apk, offset). - std::string shared_lib(bt_map.name.substr(apk_pos + 2)); - bt_map.name = bt_map.name.substr(0, apk_pos); - uint64_t offset; - uint32_t length; - if (ApkInspector::FindOffsetInApkByName(bt_map.name, shared_lib, &offset, &length)) { - bt_map.offset = offset; + // Create map only if the maps have changed since the last unwind. + auto map_it = cached_maps_.find(thread.pid); + CachedMap& cached_map = (map_it == cached_maps_.end() ? cached_maps_[thread.pid] + : map_it->second); + if (cached_map.version < thread.maps->version) { + std::vector<backtrace_map_t> bt_maps(thread.maps->maps.size()); + size_t map_index = 0; + for (auto& map : thread.maps->maps) { + backtrace_map_t& bt_map = bt_maps[map_index++]; + bt_map.start = map->start_addr; + bt_map.end = map->start_addr + map->len; + bt_map.offset = map->pgoff; + bt_map.name = map->dso->GetDebugFilePath(); + if (bt_map.offset == 0) { + size_t apk_pos = bt_map.name.find_last_of('!'); + if (apk_pos != std::string::npos) { + // The unwinder does not understand the ! format, so change back to + // the previous format (apk, offset). + std::string shared_lib(bt_map.name.substr(apk_pos + 2)); + bt_map.name = bt_map.name.substr(0, apk_pos); + uint64_t offset; + uint32_t length; + if (ApkInspector::FindOffsetInApkByName(bt_map.name, shared_lib, &offset, &length)) { + bt_map.offset = offset; + } } } + bt_map.flags = PROT_READ | PROT_EXEC; } - bt_map.flags = PROT_READ | PROT_EXEC; + cached_map.map.reset(BacktraceMap::CreateOffline(thread.pid, bt_maps)); + if (!cached_map.map) { + return false; + } + // Disable the resolving of names, this data is not used. + cached_map.map->SetResolveNames(false); + cached_map.version = thread.maps->version; } backtrace_stackinfo_t stack_info; @@ -156,16 +170,13 @@ bool OfflineUnwinder::UnwindCallChain(const ThreadEntry& thread, const RegSet& r stack_info.end = stack_addr + stack_size; stack_info.data = reinterpret_cast<const uint8_t*>(stack); - std::unique_ptr<BacktraceMap> map(BacktraceMap::CreateOffline(thread.pid, bt_maps, stack_info)); std::unique_ptr<unwindstack::Regs> unwind_regs(GetBacktraceRegs(regs)); - if (!map || !unwind_regs) { + if (!unwind_regs) { return false; } - // Disable the resolving of names, this data is not used. - map->SetResolveNames(false); std::vector<backtrace_frame_data_t> frames; BacktraceUnwindError error; - if (Backtrace::Unwind(unwind_regs.get(), map.get(), &frames, 0u, nullptr, &error)) { + if (Backtrace::UnwindOffline(unwind_regs.get(), cached_map.map.get(), stack_info, &frames, &error)) { for (auto& frame : frames) { // Unwinding in arm architecture can return 0 pc address. if (frame.pc == 0) { diff --git a/simpleperf/OfflineUnwinder.h b/simpleperf/OfflineUnwinder.h index dd57d7de..81ef3363 100644 --- a/simpleperf/OfflineUnwinder.h +++ b/simpleperf/OfflineUnwinder.h @@ -17,10 +17,14 @@ #ifndef SIMPLE_PERF_OFFLINE_UNWINDER_H_ #define SIMPLE_PERF_OFFLINE_UNWINDER_H_ +#include <memory> #include <vector> +#include <unordered_map> #include "perf_regs.h" +#include <backtrace/BacktraceMap.h> + namespace simpleperf { struct ThreadEntry; @@ -66,6 +70,14 @@ class OfflineUnwinder { private: bool collect_stat_; UnwindingResult unwinding_result_; + + // Cache of the most recently used map. + struct CachedMap { + uint64_t version = 0u; + std::unique_ptr<BacktraceMap> map; + }; + // use unused attribute to pass mac build. + std::unordered_map<pid_t, CachedMap> cached_maps_ __attribute__((unused)); }; } // namespace simpleperf diff --git a/simpleperf/thread_tree.cpp b/simpleperf/thread_tree.cpp index b19e2faf..283c697d 100644 --- a/simpleperf/thread_tree.cpp +++ b/simpleperf/thread_tree.cpp @@ -109,7 +109,7 @@ void ThreadTree::AddKernelMap(uint64_t start_addr, uint64_t len, uint64_t pgoff, MapEntry* map = AllocateMap(MapEntry(start_addr, len, pgoff, time, dso, true)); FixOverlappedMap(&kernel_maps_, map); - auto pair = kernel_maps_.insert(map); + auto pair = kernel_maps_.maps.insert(map); CHECK(pair.second); } @@ -134,8 +134,9 @@ void ThreadTree::AddThreadMap(int pid, int tid, uint64_t start_addr, MapEntry* map = AllocateMap(MapEntry(start_addr, len, pgoff, time, dso, false)); FixOverlappedMap(thread->maps, map); - auto pair = thread->maps->insert(map); + auto pair = thread->maps->maps.insert(map); CHECK(pair.second); + thread->maps->version++; } Dso* ThreadTree::FindUserDsoOrNew(const std::string& filename, uint64_t start_addr) { @@ -155,7 +156,7 @@ MapEntry* ThreadTree::AllocateMap(const MapEntry& value) { } void ThreadTree::FixOverlappedMap(MapSet* maps, const MapEntry* map) { - for (auto it = maps->begin(); it != maps->end();) { + for (auto it = maps->maps.begin(); it != maps->maps.end();) { if ((*it)->start_addr >= map->get_end_addr()) { // No more overlapped maps. break; @@ -168,17 +169,17 @@ void ThreadTree::FixOverlappedMap(MapSet* maps, const MapEntry* map) { MapEntry* before = AllocateMap( MapEntry(old->start_addr, map->start_addr - old->start_addr, old->pgoff, old->time, old->dso, old->in_kernel)); - maps->insert(before); + maps->maps.insert(before); } if (old->get_end_addr() > map->get_end_addr()) { MapEntry* after = AllocateMap(MapEntry( map->get_end_addr(), old->get_end_addr() - map->get_end_addr(), map->get_end_addr() - old->start_addr + old->pgoff, old->time, old->dso, old->in_kernel)); - maps->insert(after); + maps->maps.insert(after); } - it = maps->erase(it); + it = maps->maps.erase(it); } } } @@ -192,8 +193,8 @@ static MapEntry* FindMapByAddr(const MapSet& maps, uint64_t addr) { // on MapComparator. MapEntry find_map(addr, std::numeric_limits<uint64_t>::max(), 0, std::numeric_limits<uint64_t>::max(), nullptr, false); - auto it = maps.upper_bound(&find_map); - if (it != maps.begin() && IsAddrInMap(addr, *--it)) { + auto it = maps.maps.upper_bound(&find_map); + if (it != maps.maps.begin() && IsAddrInMap(addr, *--it)) { return *it; } return nullptr; @@ -273,7 +274,7 @@ void ThreadTree::ClearThreadAndMap() { thread_tree_.clear(); thread_comm_storage_.clear(); map_set_storage_.clear(); - kernel_maps_.clear(); + kernel_maps_.maps.clear(); map_storage_.clear(); } diff --git a/simpleperf/thread_tree.h b/simpleperf/thread_tree.h index 621bc467..a3653f5f 100644 --- a/simpleperf/thread_tree.h +++ b/simpleperf/thread_tree.h @@ -59,7 +59,10 @@ struct MapComparator { bool operator()(const MapEntry* map1, const MapEntry* map2) const; }; -using MapSet = std::set<MapEntry*, MapComparator>; +struct MapSet { + std::set<MapEntry*, MapComparator> maps; + uint64_t version = 0u; // incremented each time changing maps +}; struct ThreadEntry { int pid; |