OSDN Git Service

Simpleperf: demangle symbols only when necessary.
authorYabin Cui <yabinc@google.com>
Tue, 18 Aug 2015 23:32:18 +0000 (16:32 -0700)
committerYabin Cui <yabinc@google.com>
Wed, 19 Aug 2015 00:58:41 +0000 (17:58 -0700)
Before this change:
$sudo simpleperf record -a sleep 1
$sudo simpleperf stat simpleperf report
Total test time: 4.088779 seconds.

After this change:
$sudo simpleperf record -a sleep 1
$sudo simpleperf stat simpleperf report
Total test time: 1.226267 seconds.

Change-Id: Ifc811f432ac69f770eeb5814e4983f6f19dbc909

simpleperf/cmd_report.cpp
simpleperf/dso.cpp
simpleperf/dso.h
simpleperf/thread_tree.h

index e7f98f7..5d08993 100644 (file)
@@ -179,11 +179,12 @@ class SymbolItem : public Displayable, public Comparable {
   }
 
   int Compare(const SampleEntry& sample1, const SampleEntry& sample2) const override {
-    return strcmp(sample1.symbol->name.c_str(), sample2.symbol->name.c_str());
+    return strcmp(sample1.symbol->GetDemangledName().c_str(),
+                  sample2.symbol->GetDemangledName().c_str());
   }
 
   std::string Show(const SampleEntry& sample) const override {
-    return sample.symbol->name;
+    return sample.symbol->GetDemangledName();
   }
 };
 
@@ -214,12 +215,12 @@ class SymbolFromItem : public Displayable, public Comparable {
   }
 
   int Compare(const SampleEntry& sample1, const SampleEntry& sample2) const override {
-    return strcmp(sample1.branch_from.symbol->name.c_str(),
-                  sample2.branch_from.symbol->name.c_str());
+    return strcmp(sample1.branch_from.symbol->GetDemangledName().c_str(),
+                  sample2.branch_from.symbol->GetDemangledName().c_str());
   }
 
   std::string Show(const SampleEntry& sample) const override {
-    return sample.branch_from.symbol->name;
+    return sample.branch_from.symbol->GetDemangledName();
   }
 };
 
index ca45c2d..55963c2 100644 (file)
 #include "read_elf.h"
 #include "utils.h"
 
+const std::string& SymbolEntry::GetDemangledName() const {
+  if (demangled_name_.empty()) {
+    demangled_name_ = DsoFactory::GetInstance()->Demangle(name);
+  }
+  return demangled_name_;
+}
+
 bool SymbolComparator::operator()(const std::unique_ptr<SymbolEntry>& symbol1,
                                   const std::unique_ptr<SymbolEntry>& symbol2) {
   return symbol1->addr < symbol2->addr;
@@ -103,6 +110,33 @@ std::unique_ptr<DsoEntry> DsoFactory::CreateDso(DsoType dso_type, const std::str
   return std::unique_ptr<DsoEntry>(new DsoEntry(dso_type, path));
 }
 
+extern "C" char* __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status);
+
+std::string DsoFactory::Demangle(const std::string& name) {
+  if (!demangle_) {
+    return name;
+  }
+  int status;
+  bool is_linker_symbol = (name.find(linker_prefix) == 0);
+  const char* mangled_str = name.c_str();
+  if (is_linker_symbol) {
+    mangled_str += linker_prefix.size();
+  }
+  std::string result = name;
+  char* demangled_name = __cxa_demangle(mangled_str, nullptr, nullptr, &status);
+  if (status == 0) {
+    if (is_linker_symbol) {
+      result = std::string("[linker]") + demangled_name;
+    } else {
+      result = demangled_name;
+    }
+    free(demangled_name);
+  } else if (is_linker_symbol) {
+    result = std::string("[linker]") + mangled_str;
+  }
+  return result;
+}
+
 bool DsoFactory::LoadDso(DsoEntry* dso) {
   switch (dso->type) {
     case DSO_KERNEL:
@@ -122,24 +156,16 @@ static bool IsKernelFunctionSymbol(const KernelSymbol& symbol) {
 
 static bool KernelSymbolCallback(const KernelSymbol& kernel_symbol, DsoEntry* dso) {
   if (IsKernelFunctionSymbol(kernel_symbol)) {
-    SymbolEntry* symbol = new SymbolEntry{
-        kernel_symbol.name,  // name
-        kernel_symbol.addr,  // addr
-        0,                   // len
-    };
-    dso->symbols.insert(std::unique_ptr<SymbolEntry>(symbol));
+    dso->symbols.insert(
+        std::unique_ptr<SymbolEntry>(new SymbolEntry(kernel_symbol.name, kernel_symbol.addr, 0)));
   }
   return false;
 }
 
 static void VmlinuxSymbolCallback(const ElfFileSymbol& elf_symbol, DsoEntry* dso) {
   if (elf_symbol.is_func) {
-    SymbolEntry* symbol = new SymbolEntry{
-        elf_symbol.name,   // name
-        elf_symbol.vaddr,  // addr
-        elf_symbol.len,    // len
-    };
-    dso->symbols.insert(std::unique_ptr<SymbolEntry>(symbol));
+    dso->symbols.insert(std::unique_ptr<SymbolEntry>(
+        new SymbolEntry(elf_symbol.name, elf_symbol.vaddr, elf_symbol.len)));
   }
 }
 
@@ -182,12 +208,8 @@ bool DsoFactory::LoadKernel(DsoEntry* dso) {
 static void ParseSymbolCallback(const ElfFileSymbol& elf_symbol, DsoEntry* dso,
                                 bool (*filter)(const ElfFileSymbol&)) {
   if (filter(elf_symbol)) {
-    SymbolEntry* symbol = new SymbolEntry{
-        elf_symbol.name,           // name
-        elf_symbol.start_in_file,  // addr
-        elf_symbol.len,            // len
-    };
-    dso->symbols.insert(std::unique_ptr<SymbolEntry>(symbol));
+    dso->symbols.insert(std::unique_ptr<SymbolEntry>(
+        new SymbolEntry(elf_symbol.name, elf_symbol.start_in_file, elf_symbol.len)));
   }
 }
 
@@ -209,39 +231,11 @@ static bool SymbolFilterForDso(const ElfFileSymbol& elf_symbol) {
   return elf_symbol.is_func || (elf_symbol.is_label && elf_symbol.is_in_text_section);
 }
 
-extern "C" char* __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status);
-
-static void DemangleInPlace(std::string* name) {
-  int status;
-  bool is_linker_symbol = (name->find(linker_prefix) == 0);
-  const char* mangled_str = name->c_str();
-  if (is_linker_symbol) {
-    mangled_str += linker_prefix.size();
-  }
-  char* demangled_name = __cxa_demangle(mangled_str, nullptr, nullptr, &status);
-  if (status == 0) {
-    if (is_linker_symbol) {
-      *name = std::string("[linker]") + demangled_name;
-    } else {
-      *name = demangled_name;
-    }
-    free(demangled_name);
-  } else if (is_linker_symbol) {
-    std::string temp = std::string("[linker]") + mangled_str;
-    *name = std::move(temp);
-  }
-}
-
 bool DsoFactory::LoadElfFile(DsoEntry* dso) {
   BuildId build_id = GetExpectedBuildId(dso->path);
   ParseSymbolsFromElfFile(
       symfs_dir_ + dso->path, build_id,
       std::bind(ParseSymbolCallback, std::placeholders::_1, dso, SymbolFilterForDso));
-  if (demangle_) {
-    for (auto& symbol : dso->symbols) {
-      DemangleInPlace(&symbol->name);
-    }
-  }
   FixupSymbolLength(dso);
   return true;
 }
index 8b83000..5e44a99 100644 (file)
@@ -29,6 +29,15 @@ struct SymbolEntry {
   std::string name;
   uint64_t addr;
   uint64_t len;
+
+  SymbolEntry(const std::string& name, uint64_t addr, uint64_t len)
+      : name(name), addr(addr), len(len) {
+  }
+
+  const std::string& GetDemangledName() const;
+
+ private:
+  mutable std::string demangled_name_;
 };
 
 struct SymbolComparator {
@@ -57,11 +66,14 @@ struct DsoEntry {
 class DsoFactory {
  public:
   static DsoFactory* GetInstance();
+
   void SetDemangle(bool demangle);
   bool SetSymFsDir(const std::string& symfs_dir);
   void SetVmlinux(const std::string& vmlinux);
   void SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids);
+
   std::unique_ptr<DsoEntry> CreateDso(DsoType dso_type, const std::string& dso_path = "");
+  std::string Demangle(const std::string& name);
   bool LoadDso(DsoEntry* dso);
 
  private:
index ea52f97..c0ec3ea 100644 (file)
@@ -43,7 +43,7 @@ struct ThreadEntry {
 
 class ThreadTree {
  public:
-  ThreadTree() : unknown_dso_(DSO_ELF_FILE, "unknown") {
+  ThreadTree() : unknown_dso_(DSO_ELF_FILE, "unknown"), unknown_symbol_("unknown", 0, ULLONG_MAX) {
     unknown_map_ = MapEntry{
         0,              // start_addr
         ULLONG_MAX,     // len
@@ -51,11 +51,6 @@ class ThreadTree {
         0,              // time
         &unknown_dso_,  // dso
     };
-    unknown_symbol_ = SymbolEntry{
-        "unknown",   // name
-        0,           // addr
-        ULLONG_MAX,  // len
-    };
   }
 
   void AddThread(int pid, int tid, const std::string& comm);