summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Srbecky <dsrbecky@google.com>2018-02-23 19:25:02 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-02-23 19:25:02 +0000
commite92a2d8a4329f9d91777a81db667ef71114b5ca6 (patch)
treec177e6b666f10d9946e5f1f33e727020ac67d186
parent6e7c4df7cc2374ba72996953c74541b5a0aa7a63 (diff)
parent15933b6e39d1afbda8538a42ae206286582e54cc (diff)
downloadextras-e92a2d8a4329f9d91777a81db667ef71114b5ca6.tar.gz
Merge "Create maps for libunwind only if they changed."
-rw-r--r--simpleperf/OfflineUnwinder.cpp61
-rw-r--r--simpleperf/OfflineUnwinder.h12
-rw-r--r--simpleperf/thread_tree.cpp19
-rw-r--r--simpleperf/thread_tree.h5
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;