summaryrefslogtreecommitdiff
path: root/simpleperf/thread_tree.cpp
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2016-12-15 11:24:03 -0800
committerYabin Cui <yabinc@google.com>2016-12-16 11:45:57 -0800
commitaa0dd19abe684059d0595f343395183b864157d2 (patch)
treef0fb579589f7ee3403e8a040370a9c6bab9ceb70 /simpleperf/thread_tree.cpp
parent43b28bc67b04389bc8a803f099e1daada08b969c (diff)
downloadextras-aa0dd19abe684059d0595f343395183b864157d2.tar.gz
simpleperf: use per process maps.
Originally we use per thread maps, and copy the maps from parent thread when processing ForkRecord. But there are situations that ForkRecords are lost, then the new thread is left having no maps, which leads to unknown dso/symbols. To fix this, we can use per process maps. Even if ForkRecords are lost, we know which process a SampleRecord belongs to, and can use the process maps. This is reasonable because in most cases, new threads in the same thread group are created with both CLONE_THREAD and CLONE_VM. Bug: http://b/33503165 Test: run simpleperf_unit_test. Change-Id: If84b6cdac39cd6ad4e441ed6d75ed879b86d1830
Diffstat (limited to 'simpleperf/thread_tree.cpp')
-rw-r--r--simpleperf/thread_tree.cpp82
1 files changed, 46 insertions, 36 deletions
diff --git a/simpleperf/thread_tree.cpp b/simpleperf/thread_tree.cpp
index 09b0e1fb..c40607dc 100644
--- a/simpleperf/thread_tree.cpp
+++ b/simpleperf/thread_tree.cpp
@@ -45,23 +45,12 @@ bool MapComparator::operator()(const MapEntry* map1,
return false;
}
-void ThreadTree::AddThread(int pid, int tid, const std::string& comm) {
- auto it = thread_tree_.find(tid);
- if (it == thread_tree_.end()) {
- ThreadEntry* thread = new ThreadEntry{
- pid, tid,
- "unknown", // comm
- std::set<MapEntry*, MapComparator>(), // maps
- };
- auto pair = thread_tree_.insert(
- std::make_pair(tid, std::unique_ptr<ThreadEntry>(thread)));
- CHECK(pair.second);
- it = pair.first;
- }
- if (comm != it->second->comm) {
+void ThreadTree::SetThreadName(int pid, int tid, const std::string& comm) {
+ ThreadEntry* thread = FindThreadOrNew(pid, tid);
+ if (comm != thread->comm) {
thread_comm_storage_.push_back(
std::unique_ptr<std::string>(new std::string(comm)));
- it->second->comm = thread_comm_storage_.back()->c_str();
+ thread->comm = thread_comm_storage_.back()->c_str();
}
}
@@ -69,14 +58,16 @@ void ThreadTree::ForkThread(int pid, int tid, int ppid, int ptid) {
ThreadEntry* parent = FindThreadOrNew(ppid, ptid);
ThreadEntry* child = FindThreadOrNew(pid, tid);
child->comm = parent->comm;
- child->maps = parent->maps;
+ if (pid != ppid) {
+ // Copy maps from parent process.
+ *child->maps = *parent->maps;
+ }
}
ThreadEntry* ThreadTree::FindThreadOrNew(int pid, int tid) {
auto it = thread_tree_.find(tid);
if (it == thread_tree_.end()) {
- AddThread(pid, tid, "unknown");
- it = thread_tree_.find(tid);
+ return CreateThread(pid, tid);
} else {
if (pid != it->second.get()->pid) {
// TODO: b/22185053.
@@ -88,6 +79,26 @@ ThreadEntry* ThreadTree::FindThreadOrNew(int pid, int tid) {
return it->second.get();
}
+ThreadEntry* ThreadTree::CreateThread(int pid, int tid) {
+ MapSet* maps = nullptr;
+ if (pid == tid) {
+ maps = new MapSet;
+ map_set_storage_.push_back(std::unique_ptr<MapSet>(maps));
+ } else {
+ // Share maps among threads in the same thread group.
+ ThreadEntry* process = FindThreadOrNew(pid, pid);
+ maps = process->maps;
+ }
+ ThreadEntry* thread = new ThreadEntry{
+ pid, tid,
+ "unknown",
+ maps,
+ };
+ auto pair = thread_tree_.insert(std::make_pair(tid, std::unique_ptr<ThreadEntry>(thread)));
+ CHECK(pair.second);
+ return thread;
+}
+
void ThreadTree::AddKernelMap(uint64_t start_addr, uint64_t len, uint64_t pgoff,
uint64_t time, const std::string& filename) {
// kernel map len can be 0 when record command is not run in supervisor mode.
@@ -97,8 +108,8 @@ void ThreadTree::AddKernelMap(uint64_t start_addr, uint64_t len, uint64_t pgoff,
Dso* dso = FindKernelDsoOrNew(filename);
MapEntry* map =
AllocateMap(MapEntry(start_addr, len, pgoff, time, dso, true));
- FixOverlappedMap(&kernel_map_tree_, map);
- auto pair = kernel_map_tree_.insert(map);
+ FixOverlappedMap(&kernel_maps_, map);
+ auto pair = kernel_maps_.insert(map);
CHECK(pair.second);
}
@@ -122,8 +133,8 @@ void ThreadTree::AddThreadMap(int pid, int tid, uint64_t start_addr,
Dso* dso = FindUserDsoOrNew(filename);
MapEntry* map =
AllocateMap(MapEntry(start_addr, len, pgoff, time, dso, false));
- FixOverlappedMap(&thread->maps, map);
- auto pair = thread->maps.insert(map);
+ FixOverlappedMap(thread->maps, map);
+ auto pair = thread->maps->insert(map);
CHECK(pair.second);
}
@@ -142,9 +153,8 @@ MapEntry* ThreadTree::AllocateMap(const MapEntry& value) {
return map;
}
-void ThreadTree::FixOverlappedMap(std::set<MapEntry*, MapComparator>* map_set,
- const MapEntry* map) {
- for (auto it = map_set->begin(); it != map_set->end();) {
+void ThreadTree::FixOverlappedMap(MapSet* maps, const MapEntry* map) {
+ for (auto it = maps->begin(); it != maps->end();) {
if ((*it)->start_addr >= map->get_end_addr()) {
// No more overlapped maps.
break;
@@ -157,17 +167,17 @@ void ThreadTree::FixOverlappedMap(std::set<MapEntry*, MapComparator>* map_set,
MapEntry* before = AllocateMap(
MapEntry(old->start_addr, map->start_addr - old->start_addr,
old->pgoff, old->time, old->dso, old->in_kernel));
- map_set->insert(before);
+ 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));
- map_set->insert(after);
+ maps->insert(after);
}
- it = map_set->erase(it);
+ it = maps->erase(it);
}
}
}
@@ -176,8 +186,7 @@ static bool IsAddrInMap(uint64_t addr, const MapEntry* map) {
return (addr >= map->start_addr && addr < map->get_end_addr());
}
-static MapEntry* FindMapByAddr(const std::set<MapEntry*, MapComparator>& maps,
- uint64_t addr) {
+static MapEntry* FindMapByAddr(const MapSet& maps, uint64_t addr) {
// Construct a map_entry which is strictly after the searched map_entry, based
// on MapComparator.
MapEntry find_map(addr, std::numeric_limits<uint64_t>::max(), 0,
@@ -193,19 +202,19 @@ const MapEntry* ThreadTree::FindMap(const ThreadEntry* thread, uint64_t ip,
bool in_kernel) {
MapEntry* result = nullptr;
if (!in_kernel) {
- result = FindMapByAddr(thread->maps, ip);
+ result = FindMapByAddr(*thread->maps, ip);
} else {
- result = FindMapByAddr(kernel_map_tree_, ip);
+ result = FindMapByAddr(kernel_maps_, ip);
}
return result != nullptr ? result : &unknown_map_;
}
const MapEntry* ThreadTree::FindMap(const ThreadEntry* thread, uint64_t ip) {
- MapEntry* result = FindMapByAddr(thread->maps, ip);
+ MapEntry* result = FindMapByAddr(*thread->maps, ip);
if (result != nullptr) {
return result;
}
- result = FindMapByAddr(kernel_map_tree_, ip);
+ result = FindMapByAddr(kernel_maps_, ip);
return result != nullptr ? result : &unknown_map_;
}
@@ -252,7 +261,8 @@ const Symbol* ThreadTree::FindKernelSymbol(uint64_t ip) {
void ThreadTree::ClearThreadAndMap() {
thread_tree_.clear();
thread_comm_storage_.clear();
- kernel_map_tree_.clear();
+ map_set_storage_.clear();
+ kernel_maps_.clear();
map_storage_.clear();
}
@@ -293,7 +303,7 @@ void ThreadTree::Update(const Record& record) {
}
} else if (record.type() == PERF_RECORD_COMM) {
const CommRecord& r = *static_cast<const CommRecord*>(&record);
- AddThread(r.data->pid, r.data->tid, r.comm);
+ SetThreadName(r.data->pid, r.data->tid, r.comm);
} else if (record.type() == PERF_RECORD_FORK) {
const ForkRecord& r = *static_cast<const ForkRecord*>(&record);
ForkThread(r.data->pid, r.data->tid, r.data->ppid, r.data->ptid);