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));
}
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);
const char* dso_name;
uint64_t vaddr_in_file;
const char* symbol_name;
+ uint64_t symbol_addr;
};
struct CallChainEntry {
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 {
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_;
SymbolEntry current_symbol_;
CallChain current_callchain_;
std::vector<CallChainEntry> callchain_entries_;
+ std::string build_id_string_;
int update_flag_;
std::vector<EventAttrWithName> event_attrs_;
};
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)) {
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 ¤t_symbol_;
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);
}
}
return ¤t_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();
CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) {
return report_lib->GetCallChainOfCurrentSample();
}
+
+const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) {
+ return report_lib->GetBuildIdForPath(path);
+}
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__))
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):
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),
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):
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))
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")
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