OSDN Git Service

Merge "simpleperf: restore perf_harden after simpleperf cts test." into nyc-dev
[android-x86/system-extras.git] / simpleperf / sample_tree.cpp
index ce09246..a34107b 100644 (file)
 
 #include "sample_tree.h"
 
-#include <base/logging.h>
+#include <android-base/logging.h>
 
 #include "environment.h"
 
-bool MapComparator::operator()(const MapEntry* map1, const MapEntry* map2) const {
-  if (map1->start_addr != map2->start_addr) {
-    return map1->start_addr < map2->start_addr;
-  }
-  if (map1->len != map2->len) {
-    return map1->len < map2->len;
-  }
-  if (map1->time != map2->time) {
-    return map1->time < map2->time;
-  }
-  return false;
-}
-
-void SampleTree::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;
-  }
-  thread_comm_storage_.push_back(std::unique_ptr<std::string>(new std::string(comm)));
-  it->second->comm = thread_comm_storage_.back()->c_str();
-}
-
-void SampleTree::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;
-}
-
-static void RemoveOverlappedMap(std::set<MapEntry*, MapComparator>* map_set, const MapEntry* map) {
-  for (auto it = map_set->begin(); it != map_set->end();) {
-    if ((*it)->start_addr >= map->start_addr + map->len) {
-      break;
-    }
-    if ((*it)->start_addr + (*it)->len <= map->start_addr) {
-      ++it;
-    } else {
-      it = map_set->erase(it);
-    }
-  }
-}
-
-void SampleTree::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.
-  if (len == 0) {
-    return;
-  }
-  DsoEntry* dso = FindKernelDsoOrNew(filename);
-  MapEntry* map = new MapEntry{
-      start_addr, len, pgoff, time, dso,
-  };
-  map_storage_.push_back(std::unique_ptr<MapEntry>(map));
-  RemoveOverlappedMap(&kernel_map_tree_, map);
-  auto pair = kernel_map_tree_.insert(map);
-  CHECK(pair.second);
-}
-
-DsoEntry* SampleTree::FindKernelDsoOrNew(const std::string& filename) {
-  if (filename == DEFAULT_KERNEL_MMAP_NAME) {
-    if (kernel_dso_ == nullptr) {
-      kernel_dso_ = DsoFactory::GetInstance()->LoadKernel();
-    }
-    return kernel_dso_.get();
-  }
-  auto it = module_dso_tree_.find(filename);
-  if (it == module_dso_tree_.end()) {
-    module_dso_tree_[filename] = DsoFactory::GetInstance()->LoadKernelModule(filename);
-    it = module_dso_tree_.find(filename);
-  }
-  return it->second.get();
-}
-
-void SampleTree::AddThreadMap(int pid, int tid, uint64_t start_addr, uint64_t len, uint64_t pgoff,
-                              uint64_t time, const std::string& filename) {
-  ThreadEntry* thread = FindThreadOrNew(pid, tid);
-  DsoEntry* dso = FindUserDsoOrNew(filename);
-  MapEntry* map = new MapEntry{
-      start_addr, len, pgoff, time, dso,
-  };
-  map_storage_.push_back(std::unique_ptr<MapEntry>(map));
-  RemoveOverlappedMap(&thread->maps, map);
-  auto pair = thread->maps.insert(map);
-  CHECK(pair.second);
-}
-
-ThreadEntry* SampleTree::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);
-  } else {
-    CHECK_EQ(pid, it->second.get()->pid) << "tid = " << tid;
-  }
-  return it->second.get();
-}
-
-DsoEntry* SampleTree::FindUserDsoOrNew(const std::string& filename) {
-  auto it = user_dso_tree_.find(filename);
-  if (it == user_dso_tree_.end()) {
-    user_dso_tree_[filename] = DsoFactory::GetInstance()->LoadDso(filename);
-    it = user_dso_tree_.find(filename);
-  }
-  return it->second.get();
-}
-
-static bool IsIpInMap(uint64_t ip, const MapEntry* map) {
-  return (map->start_addr <= ip && map->start_addr + map->len > ip);
-}
-
-const MapEntry* SampleTree::FindMap(const ThreadEntry* thread, uint64_t ip, bool in_kernel) {
-  // Construct a map_entry which is strictly after the searched map_entry, based on MapComparator.
-  MapEntry find_map = {
-      ip,          // start_addr
-      ULLONG_MAX,  // len
-      0,           // pgoff
-      ULLONG_MAX,  // time
-      nullptr,     // dso
-  };
-  if (!in_kernel) {
-    auto it = thread->maps.upper_bound(&find_map);
-    if (it != thread->maps.begin() && IsIpInMap(ip, *--it)) {
-      return *it;
-    }
-  } else {
-    auto it = kernel_map_tree_.upper_bound(&find_map);
-    if (it != kernel_map_tree_.begin() && IsIpInMap(ip, *--it)) {
-      return *it;
-    }
-  }
-  return &unknown_map_;
+void SampleTree::SetFilters(const std::unordered_set<int>& pid_filter,
+                            const std::unordered_set<int>& tid_filter,
+                            const std::unordered_set<std::string>& comm_filter,
+                            const std::unordered_set<std::string>& dso_filter) {
+  pid_filter_ = pid_filter;
+  tid_filter_ = tid_filter;
+  comm_filter_ = comm_filter;
+  dso_filter_ = dso_filter;
 }
 
 SampleEntry* SampleTree::AddSample(int pid, int tid, uint64_t ip, uint64_t time, uint64_t period,
                                    bool in_kernel) {
-  const ThreadEntry* thread = FindThreadOrNew(pid, tid);
-  const MapEntry* map = FindMap(thread, ip, in_kernel);
-  const SymbolEntry* symbol = FindSymbol(map, ip);
+  const ThreadEntry* thread = thread_tree_->FindThreadOrNew(pid, tid);
+  const MapEntry* map = thread_tree_->FindMap(thread, ip, in_kernel);
+  const Symbol* symbol = thread_tree_->FindSymbol(map, ip);
 
   SampleEntry value(ip, time, period, 0, 1, thread, map, symbol);
 
+  if (IsFilteredOut(value)) {
+    return nullptr;
+  }
   return InsertSample(value);
 }
 
 void SampleTree::AddBranchSample(int pid, int tid, uint64_t from_ip, uint64_t to_ip,
                                  uint64_t branch_flags, uint64_t time, uint64_t period) {
-  const ThreadEntry* thread = FindThreadOrNew(pid, tid);
-  const MapEntry* from_map = FindMap(thread, from_ip, false);
-  if (from_map == &unknown_map_) {
-    from_map = FindMap(thread, from_ip, true);
+  const ThreadEntry* thread = thread_tree_->FindThreadOrNew(pid, tid);
+  const MapEntry* from_map = thread_tree_->FindMap(thread, from_ip, false);
+  if (from_map == thread_tree_->UnknownMap()) {
+    from_map = thread_tree_->FindMap(thread, from_ip, true);
   }
-  const SymbolEntry* from_symbol = FindSymbol(from_map, from_ip);
-  const MapEntry* to_map = FindMap(thread, to_ip, false);
-  if (to_map == &unknown_map_) {
-    to_map = FindMap(thread, to_ip, true);
+  const Symbol* from_symbol = thread_tree_->FindSymbol(from_map, from_ip);
+  const MapEntry* to_map = thread_tree_->FindMap(thread, to_ip, false);
+  if (to_map == thread_tree_->UnknownMap()) {
+    to_map = thread_tree_->FindMap(thread, to_ip, true);
   }
-  const SymbolEntry* to_symbol = FindSymbol(to_map, to_ip);
+  const Symbol* to_symbol = thread_tree_->FindSymbol(to_map, to_ip);
 
   SampleEntry value(to_ip, time, period, 0, 1, thread, to_map, to_symbol);
   value.branch_from.ip = from_ip;
@@ -191,18 +64,32 @@ void SampleTree::AddBranchSample(int pid, int tid, uint64_t from_ip, uint64_t to
   value.branch_from.symbol = from_symbol;
   value.branch_from.flags = branch_flags;
 
+  if (IsFilteredOut(value)) {
+    return;
+  }
   InsertSample(value);
 }
 
 SampleEntry* SampleTree::AddCallChainSample(int pid, int tid, uint64_t ip, uint64_t time,
                                             uint64_t period, bool in_kernel,
                                             const std::vector<SampleEntry*>& callchain) {
-  const ThreadEntry* thread = FindThreadOrNew(pid, tid);
-  const MapEntry* map = FindMap(thread, ip, in_kernel);
-  const SymbolEntry* symbol = FindSymbol(map, ip);
+  const ThreadEntry* thread = thread_tree_->FindThreadOrNew(pid, tid);
+  const MapEntry* map = thread_tree_->FindMap(thread, ip, in_kernel);
+  const Symbol* symbol = thread_tree_->FindSymbol(map, ip);
 
   SampleEntry value(ip, time, 0, period, 0, thread, map, symbol);
 
+  if (IsFilteredOut(value)) {
+    // Store in callchain_sample_tree_ for use in other SampleEntry's callchain.
+    auto it = callchain_sample_tree_.find(&value);
+    if (it != callchain_sample_tree_.end()) {
+      return *it;
+    }
+    SampleEntry* sample = AllocateSample(value);
+    callchain_sample_tree_.insert(sample);
+    return sample;
+  }
+
   auto it = sample_tree_.find(&value);
   if (it != sample_tree_.end()) {
     SampleEntry* sample = *it;
@@ -214,6 +101,22 @@ SampleEntry* SampleTree::AddCallChainSample(int pid, int tid, uint64_t ip, uint6
   return InsertSample(value);
 }
 
+bool SampleTree::IsFilteredOut(const SampleEntry& value) {
+  if (!pid_filter_.empty() && pid_filter_.find(value.thread->pid) == pid_filter_.end()) {
+    return true;
+  }
+  if (!tid_filter_.empty() && tid_filter_.find(value.thread->tid) == tid_filter_.end()) {
+    return true;
+  }
+  if (!comm_filter_.empty() && comm_filter_.find(value.thread_comm) == comm_filter_.end()) {
+    return true;
+  }
+  if (!dso_filter_.empty() && dso_filter_.find(value.map->dso->Path()) == dso_filter_.end()) {
+    return true;
+  }
+  return false;
+}
+
 SampleEntry* SampleTree::InsertSample(SampleEntry& value) {
   SampleEntry* result;
   auto it = sample_tree_.find(&value);
@@ -238,20 +141,6 @@ SampleEntry* SampleTree::AllocateSample(SampleEntry& value) {
   return sample;
 }
 
-const SymbolEntry* SampleTree::FindSymbol(const MapEntry* map, uint64_t ip) {
-  uint64_t offset_in_file;
-  if (map->dso == kernel_dso_.get()) {
-    offset_in_file = ip;
-  } else {
-    offset_in_file = ip - map->start_addr + map->pgoff;
-  }
-  const SymbolEntry* symbol = map->dso->FindSymbol(offset_in_file);
-  if (symbol == nullptr) {
-    symbol = &unknown_symbol_;
-  }
-  return symbol;
-}
-
 void SampleTree::InsertCallChainForSample(SampleEntry* sample,
                                           const std::vector<SampleEntry*>& callchain,
                                           uint64_t period) {