OSDN Git Service

Merge "simpleperf: add stuff in report_lib_interface."
authorYabin Cui <yabinc@google.com>
Tue, 29 Nov 2016 19:46:07 +0000 (19:46 +0000)
committerGerrit Code Review <noreply-gerritcodereview@google.com>
Tue, 29 Nov 2016 19:46:08 +0000 (19:46 +0000)
simpleperf/dso.cpp
simpleperf/dso.h
simpleperf/report_lib_interface.cpp
simpleperf/scripts/libsimpleperf_report.so
simpleperf/scripts/simpleperf_report_lib.py

index c889416..d52c445 100644 (file)
@@ -118,14 +118,18 @@ void Dso::SetBuildIds(
   build_id_map_ = std::move(map);
 }
 
-BuildId Dso::GetExpectedBuildId() {
-  auto it = build_id_map_.find(path_);
+BuildId Dso::FindExpectedBuildIdForPath(const std::string& path) {
+  auto it = build_id_map_.find(path);
   if (it != build_id_map_.end()) {
     return it->second;
   }
   return BuildId();
 }
 
+BuildId Dso::GetExpectedBuildId() {
+  return FindExpectedBuildIdForPath(path_);
+}
+
 std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type,
                                     const std::string& dso_path) {
   return std::unique_ptr<Dso>(new Dso(dso_type, dso_path));
index 17b3988..7102f0e 100644 (file)
@@ -92,6 +92,7 @@ class Dso {
   }
   static void SetBuildIds(
       const std::vector<std::pair<std::string, BuildId>>& build_ids);
+  static BuildId FindExpectedBuildIdForPath(const std::string& path);
 
   static std::unique_ptr<Dso> CreateDso(DsoType dso_type,
                                         const std::string& dso_path);
index 2aa0ccc..abd0962 100644 (file)
@@ -51,6 +51,7 @@ struct SymbolEntry {
   const char* dso_name;
   uint64_t vaddr_in_file;
   const char* symbol_name;
+  uint64_t symbol_addr;
 };
 
 struct CallChainEntry {
@@ -80,6 +81,8 @@ Sample* GetNextSample(ReportLib* report_lib) EXPORT;
 Event* GetEventOfCurrentSample(ReportLib* report_lib) EXPORT;
 SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) EXPORT;
 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) EXPORT;
+
+const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) EXPORT;
 }
 
 struct EventAttrWithName {
@@ -122,8 +125,11 @@ class ReportLib {
   SymbolEntry* GetSymbolOfCurrentSample();
   CallChain* GetCallChainOfCurrentSample();
 
+  const char* GetBuildIdForPath(const char* path);
+
  private:
   Sample* GetCurrentSample();
+  bool OpenRecordFileIfNecessary();
 
   std::unique_ptr<android::base::ScopedLogSeverity> log_severity_;
   std::string record_filename_;
@@ -136,6 +142,7 @@ class ReportLib {
   SymbolEntry current_symbol_;
   CallChain current_callchain_;
   std::vector<CallChainEntry> callchain_entries_;
+  std::string build_id_string_;
   int update_flag_;
   std::vector<EventAttrWithName> event_attrs_;
 };
@@ -161,15 +168,21 @@ bool ReportLib::SetKallsymsFile(const char* kallsyms_file) {
   return true;
 }
 
-
-Sample* ReportLib::GetNextSample() {
+bool ReportLib::OpenRecordFileIfNecessary() {
   if (record_file_reader_ == nullptr) {
     record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
     if (record_file_reader_ == nullptr) {
-      return nullptr;
+      return false;
     }
     record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_);
   }
+  return true;
+}
+
+Sample* ReportLib::GetNextSample() {
+  if (!OpenRecordFileIfNecessary()) {
+    return nullptr;
+  }
   while (true) {
     std::unique_ptr<Record> record;
     if (!record_file_reader_->ReadRecord(record)) {
@@ -236,6 +249,7 @@ SymbolEntry* ReportLib::GetSymbolOfCurrentSample() {
     current_symbol_.dso_name = map->dso->Path().c_str();
     current_symbol_.vaddr_in_file = vaddr_in_file;
     current_symbol_.symbol_name = symbol->DemangledName();
+    current_symbol_.symbol_addr = symbol->addr;
     update_flag_ |= UPDATE_FLAG_OF_SYMBOL;
   }
   return &current_symbol_;
@@ -281,6 +295,7 @@ CallChain* ReportLib::GetCallChainOfCurrentSample() {
           entry.symbol.dso_name = map->dso->Path().c_str();
           entry.symbol.vaddr_in_file = vaddr_in_file;
           entry.symbol.symbol_name = symbol->DemangledName();
+          entry.symbol.symbol_addr = symbol->addr;
           callchain_entries_.push_back(entry);
         }
       }
@@ -292,6 +307,20 @@ CallChain* ReportLib::GetCallChainOfCurrentSample() {
   return &current_callchain_;
 }
 
+const char* ReportLib::GetBuildIdForPath(const char* path) {
+  if (!OpenRecordFileIfNecessary()) {
+    build_id_string_.clear();
+    return build_id_string_.c_str();
+  }
+  BuildId build_id = Dso::FindExpectedBuildIdForPath(path);
+  if (build_id.IsEmpty()) {
+    build_id_string_.clear();
+  } else {
+    build_id_string_ = build_id.ToString();
+  }
+  return build_id_string_.c_str();
+}
+
 // Exported methods working with a client created instance
 ReportLib* CreateReportLib() {
   return new ReportLib();
@@ -336,3 +365,7 @@ SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) {
 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) {
   return report_lib->GetCallChainOfCurrentSample();
 }
+
+const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) {
+  return report_lib->GetBuildIdForPath(path);
+}
index ee3bff3..8682534 100755 (executable)
Binary files a/simpleperf/scripts/libsimpleperf_report.so and b/simpleperf/scripts/libsimpleperf_report.so differ
index 05ad8f0..1ccecdc 100644 (file)
 
 import ctypes as ct
 import os
+import subprocess
 import sys
+import unittest
 
 
 def _isWindows():
     return sys.platform == 'win32' or sys.platform == 'cygwin'
 
 
-def _get_script_path():
+def _get_script_dir():
     return os.path.dirname(os.path.realpath(__file__))
 
 
@@ -40,7 +42,7 @@ def _get_native_lib():
     else:
         so_name = 'libsimpleperf_report.so'
 
-    return os.path.join(_get_script_path(), so_name)
+    return os.path.join(_get_script_dir(), so_name)
 
 
 def _is_null(p):
@@ -55,6 +57,13 @@ def _char_pt(str):
     return str.encode('utf-8')
 
 
+def _char_pt_to_str(char_pt):
+    if sys.version_info < (3, 0):
+        return char_pt
+    return char_pt.decode('utf-8')
+
+
+# TODO: convert fields of type c_char_p into str for python3.
 class SampleStruct(ct.Structure):
     _fields_ = [('ip', ct.c_uint64),
                 ('pid', ct.c_uint32),
@@ -73,7 +82,8 @@ class EventStruct(ct.Structure):
 class SymbolStruct(ct.Structure):
     _fields_ = [('dso_name', ct.c_char_p),
                 ('vaddr_in_file', ct.c_uint64),
-                ('symbol_name', ct.c_char_p)]
+                ('symbol_name', ct.c_char_p),
+                ('symbol_addr', ct.c_uint64)]
 
 
 class CallChainEntryStructure(ct.Structure):
@@ -114,6 +124,8 @@ class ReportLib(object):
         self._GetCallChainOfCurrentSampleFunc = self._lib.GetCallChainOfCurrentSample
         self._GetCallChainOfCurrentSampleFunc.restype = ct.POINTER(
             CallChainStructure)
+        self._GetBuildIdForPathFunc = self._lib.GetBuildIdForPath
+        self._GetBuildIdForPathFunc.restype = ct.c_char_p
         self._instance = self._CreateReportLibFunc()
         assert(not _is_null(self._instance))
 
@@ -175,6 +187,11 @@ class ReportLib(object):
         assert(not _is_null(callchain))
         return callchain
 
+    def GetBuildIdForPath(self, path):
+        build_id = self._GetBuildIdForPathFunc(self.getInstance(), _char_pt(path))
+        assert(not _is_null(build_id))
+        return _char_pt_to_str(build_id)
+
     def getInstance(self):
         if self._instance is None:
             raise Exception("Instance is Closed")
@@ -183,3 +200,51 @@ class ReportLib(object):
     def _check(self, cond, failmsg):
         if not cond:
             raise Exception(failmsg)
+
+
+class TestReportLib(unittest.TestCase):
+    def setUp(self):
+        self.perf_data_path = os.path.join(os.path.dirname(_get_script_dir()),
+                                           'testdata', 'perf_with_symbols.data')
+        if not os.path.isfile(self.perf_data_path):
+            raise Exception("can't find perf_data at %s" % self.perf_data_path)
+        self.report_lib = ReportLib()
+        self.report_lib.SetRecordFile(self.perf_data_path)
+
+    def tearDown(self):
+        self.report_lib.Close()
+
+    def test_build_id(self):
+        build_id = self.report_lib.GetBuildIdForPath('/data/t2')
+        self.assertEqual(build_id, '0x70f1fe24500fc8b0d9eb477199ca1ca21acca4de')
+
+    def test_symbol_addr(self):
+        met_func2 = False
+        while True:
+            sample = self.report_lib.GetNextSample()
+            if sample is None:
+                break
+            event = self.report_lib.GetEventOfCurrentSample()
+            symbol = self.report_lib.GetSymbolOfCurrentSample()
+            symbol_name = _char_pt_to_str(symbol[0].symbol_name)
+            if symbol_name == 'func2(int, int)':
+                met_func2 = True
+                self.assertEqual(symbol[0].symbol_addr, 0x4004ed)
+        self.assertTrue(met_func2)
+
+
+def main():
+    test_all = True
+    if len(sys.argv) > 1 and sys.argv[1] == '--test-one':
+        test_all = False
+        del sys.argv[1]
+
+    if test_all:
+        subprocess.check_call(['python', os.path.realpath(__file__), '--test-one'])
+        subprocess.check_call(['python3', os.path.realpath(__file__), '--test-one'])
+    else:
+        sys.exit(unittest.main())
+
+
+if __name__ == '__main__':
+    main()
\ No newline at end of file