Simpleperf: load symbols from dso file only when necessary.

Bug: 22630113
Change-Id: I12bb24ec02ba3ddb94bcb2a26ae2d6e7b445ed4d
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index ec8fbaa..2b63641 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -27,7 +27,15 @@
   return symbol1->addr < symbol2->addr;
 }
 
+DsoEntry::DsoEntry(DsoType type, const std::string& path)
+    : type(type), path(path), is_loaded(false) {
+}
+
 const SymbolEntry* DsoEntry::FindSymbol(uint64_t offset_in_dso) {
+  if (!is_loaded) {
+    DsoFactory::GetInstance()->LoadDso(this);
+    is_loaded = true;
+  }
   std::unique_ptr<SymbolEntry> symbol(new SymbolEntry{
       "",             // name
       offset_in_dso,  // addr
@@ -87,6 +95,27 @@
   build_id_map_ = std::move(map);
 }
 
+std::unique_ptr<DsoEntry> DsoFactory::CreateDso(DsoType dso_type, const std::string& dso_path) {
+  std::string path = dso_path;
+  if (dso_type == DSO_KERNEL) {
+    path = "[kernel.kallsyms]";
+  }
+  return std::unique_ptr<DsoEntry>(new DsoEntry(dso_type, path));
+}
+
+bool DsoFactory::LoadDso(DsoEntry* dso) {
+  switch (dso->type) {
+    case DSO_KERNEL:
+      return LoadKernel(dso);
+    case DSO_KERNEL_MODULE:
+      return LoadKernelModule(dso);
+    case DSO_ELF_FILE:
+      return LoadElfFile(dso);
+    default:
+      return false;
+  }
+}
+
 static bool IsKernelFunctionSymbol(const KernelSymbol& symbol) {
   return (symbol.type == 'T' || symbol.type == 't' || symbol.type == 'W' || symbol.type == 'w');
 }
@@ -127,13 +156,11 @@
   }
 }
 
-std::unique_ptr<DsoEntry> DsoFactory::LoadKernel() {
-  std::unique_ptr<DsoEntry> dso(new DsoEntry);
-  dso->path = "[kernel.kallsyms]";
+bool DsoFactory::LoadKernel(DsoEntry* dso) {
   BuildId build_id = GetExpectedBuildId(DEFAULT_KERNEL_FILENAME_FOR_BUILD_ID);
   if (!vmlinux_.empty()) {
     ParseSymbolsFromElfFile(vmlinux_, build_id,
-                            std::bind(VmlinuxSymbolCallback, std::placeholders::_1, dso.get()));
+                            std::bind(VmlinuxSymbolCallback, std::placeholders::_1, dso));
   } else {
     BuildId real_build_id;
     GetKernelBuildId(&real_build_id);
@@ -142,10 +169,10 @@
                << build_id.ToString() << ", real " << real_build_id.ToString();
     if (match) {
       ProcessKernelSymbols("/proc/kallsyms",
-                           std::bind(&KernelSymbolCallback, std::placeholders::_1, dso.get()));
+                           std::bind(&KernelSymbolCallback, std::placeholders::_1, dso));
     }
   }
-  FixupSymbolLength(dso.get());
+  FixupSymbolLength(dso);
   return dso;
 }
 
@@ -166,14 +193,12 @@
   return (elf_symbol.is_func && elf_symbol.is_in_text_section);
 }
 
-std::unique_ptr<DsoEntry> DsoFactory::LoadKernelModule(const std::string& dso_path) {
-  std::unique_ptr<DsoEntry> dso(new DsoEntry);
-  dso->path = dso_path;
-  BuildId build_id = GetExpectedBuildId(dso_path);
-  ParseSymbolsFromElfFile(symfs_dir_ + dso_path, build_id,
-                          std::bind(ParseSymbolCallback, std::placeholders::_1, dso.get(),
-                                    SymbolFilterForKernelModule));
-  FixupSymbolLength(dso.get());
+bool DsoFactory::LoadKernelModule(DsoEntry* dso) {
+  BuildId build_id = GetExpectedBuildId(dso->path);
+  ParseSymbolsFromElfFile(
+      symfs_dir_ + dso->path, build_id,
+      std::bind(ParseSymbolCallback, std::placeholders::_1, dso, SymbolFilterForKernelModule));
+  FixupSymbolLength(dso);
   return dso;
 }
 
@@ -204,19 +229,17 @@
   }
 }
 
-std::unique_ptr<DsoEntry> DsoFactory::LoadDso(const std::string& dso_path) {
-  std::unique_ptr<DsoEntry> dso(new DsoEntry);
-  dso->path = dso_path;
-  BuildId build_id = GetExpectedBuildId(dso_path);
+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.get(), SymbolFilterForDso));
+      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.get());
+  FixupSymbolLength(dso);
   return dso;
 }
 
diff --git a/simpleperf/dso.h b/simpleperf/dso.h
index ba105c1..8b83000 100644
--- a/simpleperf/dso.h
+++ b/simpleperf/dso.h
@@ -36,11 +36,22 @@
                   const std::unique_ptr<SymbolEntry>& symbol2);
 };
 
+enum DsoType {
+  DSO_KERNEL,
+  DSO_KERNEL_MODULE,
+  DSO_ELF_FILE,
+};
+
 struct DsoEntry {
+  DsoType type;
   std::string path;
   std::set<std::unique_ptr<SymbolEntry>, SymbolComparator> symbols;
 
+  DsoEntry(DsoType type, const std::string& path);
   const SymbolEntry* FindSymbol(uint64_t offset_in_dso);
+
+ private:
+  bool is_loaded;
 };
 
 class DsoFactory {
@@ -50,12 +61,14 @@
   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> LoadKernel();
-  std::unique_ptr<DsoEntry> LoadKernelModule(const std::string& dso_path);
-  std::unique_ptr<DsoEntry> LoadDso(const std::string& dso_path);
+  std::unique_ptr<DsoEntry> CreateDso(DsoType dso_type, const std::string& dso_path = "");
+  bool LoadDso(DsoEntry* dso);
 
  private:
   DsoFactory();
+  bool LoadKernel(DsoEntry* dso);
+  bool LoadKernelModule(DsoEntry* dso);
+  bool LoadElfFile(DsoEntry* dso);
   BuildId GetExpectedBuildId(const std::string& filename);
 
   bool demangle_;
diff --git a/simpleperf/sample_tree.cpp b/simpleperf/sample_tree.cpp
index ce09246..6d0b403 100644
--- a/simpleperf/sample_tree.cpp
+++ b/simpleperf/sample_tree.cpp
@@ -88,13 +88,13 @@
 DsoEntry* SampleTree::FindKernelDsoOrNew(const std::string& filename) {
   if (filename == DEFAULT_KERNEL_MMAP_NAME) {
     if (kernel_dso_ == nullptr) {
-      kernel_dso_ = DsoFactory::GetInstance()->LoadKernel();
+      kernel_dso_ = DsoFactory::GetInstance()->CreateDso(DSO_KERNEL);
     }
     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);
+    module_dso_tree_[filename] = DsoFactory::GetInstance()->CreateDso(DSO_KERNEL_MODULE, filename);
     it = module_dso_tree_.find(filename);
   }
   return it->second.get();
@@ -127,7 +127,7 @@
 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);
+    user_dso_tree_[filename] = DsoFactory::GetInstance()->CreateDso(DSO_ELF_FILE, filename);
     it = user_dso_tree_.find(filename);
   }
   return it->second.get();
diff --git a/simpleperf/sample_tree.h b/simpleperf/sample_tree.h
index 2e97ceb..4e51aca 100644
--- a/simpleperf/sample_tree.h
+++ b/simpleperf/sample_tree.h
@@ -93,7 +93,8 @@
 class SampleTree {
  public:
   SampleTree(compare_sample_func_t sample_compare_function)
-      : sample_comparator_(sample_compare_function),
+      : unknown_dso_(DSO_ELF_FILE, "unknown"),
+        sample_comparator_(sample_compare_function),
         sample_tree_(sample_comparator_),
         sorted_sample_comparator_(sample_compare_function),
         sorted_sample_tree_(sorted_sample_comparator_),
@@ -106,7 +107,6 @@
         0,              // time
         &unknown_dso_,  // dso
     };
-    unknown_dso_.path = "unknown";
     unknown_symbol_ = SymbolEntry{
         "unknown",   // name
         0,           // addr