diff options
author | Yabin Cui <yabinc@google.com> | 2019-10-07 17:44:05 -0700 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2019-10-08 12:32:16 -0700 |
commit | 76554a4e55c760595abd6857d846193f60252863 (patch) | |
tree | a7ce85671da6c68a42cd25d6aa19b00eeb8d48ec | |
parent | 955434d2fce94b8fe4aa392411e768150ecb874c (diff) | |
download | extras-76554a4e55c760595abd6857d846193f60252863.tar.gz |
simpleperf: merge jitted and interpreted java methods.
Bug: 132370901
Test: run test.py TestReportLib.test_merge_java_methods.
Change-Id: I9e2cc9a0db6a6f94611947c4f146a51aff85d593
-rw-r--r-- | simpleperf/report_lib_interface.cpp | 35 | ||||
-rw-r--r-- | simpleperf/scripts/simpleperf_report_lib.py | 12 | ||||
-rwxr-xr-x | simpleperf/scripts/test.py | 25 |
3 files changed, 72 insertions, 0 deletions
diff --git a/simpleperf/report_lib_interface.cpp b/simpleperf/report_lib_interface.cpp index d685ddf5..70a274f4 100644 --- a/simpleperf/report_lib_interface.cpp +++ b/simpleperf/report_lib_interface.cpp @@ -108,6 +108,7 @@ bool SetRecordFile(ReportLib* report_lib, const char* record_file) EXPORT; bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) EXPORT; void ShowIpForUnknownSymbol(ReportLib* report_lib) EXPORT; void ShowArtFrames(ReportLib* report_lib, bool show) EXPORT; +void MergeJavaMethods(ReportLib* report_lib, bool merge) EXPORT; Sample* GetNextSample(ReportLib* report_lib) EXPORT; Event* GetEventOfCurrentSample(ReportLib* report_lib) EXPORT; @@ -154,6 +155,7 @@ class ReportLib { void ShowIpForUnknownSymbol() { thread_tree_.ShowIpForUnknownSymbol(); } void ShowArtFrames(bool show) { show_art_frames_ = show; } + void MergeJavaMethods(bool merge) { merge_java_methods_ = merge; } Sample* GetNextSample(); Event* GetEventOfCurrentSample() { return ¤t_event_; } @@ -192,6 +194,9 @@ class ReportLib { FeatureSection feature_section_; std::vector<char> feature_section_data_; bool show_art_frames_; + bool merge_java_methods_ = true; + // Map from a java method name to it's dex file, start_addr and len. + std::unordered_map<std::string, std::tuple<Dso*, uint64_t, uint64_t>> java_methods_; std::unique_ptr<Tracing> tracing_; }; @@ -227,6 +232,15 @@ bool ReportLib::OpenRecordFileIfNecessary() { if (auto it = meta_info.find("trace_offcpu"); it != meta_info.end()) { trace_offcpu_ = it->second == "true"; } + if (merge_java_methods_) { + for (Dso* dso : thread_tree_.GetAllDsos()) { + if (dso->type() == DSO_DEX_FILE) { + for (auto& symbol : dso->GetSymbols()) { + java_methods_[symbol.Name()] = std::make_tuple(dso, symbol.addr, symbol.len); + } + } + } + } } return true; } @@ -328,6 +342,23 @@ void ReportLib::SetCurrentSample() { entry.symbol.symbol_addr = symbol->addr; entry.symbol.symbol_len = symbol->len; entry.symbol.mapping = AddMapping(*map); + + if (merge_java_methods_ && map->dso->type() == DSO_ELF_FILE && map->dso->IsForJavaMethod()) { + // This is a jitted java method, merge it with the interpreted java method having the same + // name if possible. Otherwise, merge it with other jitted java methods having the same name + // by assigning a common dso_name. + if (auto it = java_methods_.find(entry.symbol.symbol_name); it != java_methods_.end()) { + entry.symbol.dso_name = std::get<0>(it->second)->Path().c_str(); + entry.symbol.symbol_addr = std::get<1>(it->second); + entry.symbol.symbol_len = std::get<2>(it->second); + // Not enough info to map an offset in a jitted method to an offset in a dex file. So just + // use the symbol_addr. + entry.symbol.vaddr_in_file = entry.symbol.symbol_addr; + } else { + entry.symbol.dso_name = "[JIT cache]"; + } + } + callchain_entries_.push_back(entry); } current_sample_.ip = callchain_entries_[0].ip; @@ -460,6 +491,10 @@ void ShowArtFrames(ReportLib* report_lib, bool show) { return report_lib->ShowArtFrames(show); } +void MergeJavaMethods(ReportLib* report_lib, bool merge) { + return report_lib->MergeJavaMethods(merge); +} + bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) { return report_lib->SetKallsymsFile(kallsyms_file); } diff --git a/simpleperf/scripts/simpleperf_report_lib.py b/simpleperf/scripts/simpleperf_report_lib.py index ab45b67a..3e677be5 100644 --- a/simpleperf/scripts/simpleperf_report_lib.py +++ b/simpleperf/scripts/simpleperf_report_lib.py @@ -240,6 +240,7 @@ class ReportLib(object): self._SetKallsymsFileFunc = self._lib.SetKallsymsFile self._ShowIpForUnknownSymbolFunc = self._lib.ShowIpForUnknownSymbol self._ShowArtFramesFunc = self._lib.ShowArtFrames + self._MergeJavaMethodsFunc = self._lib.MergeJavaMethods self._GetNextSampleFunc = self._lib.GetNextSample self._GetNextSampleFunc.restype = ct.POINTER(SampleStruct) self._GetEventOfCurrentSampleFunc = self._lib.GetEventOfCurrentSample @@ -294,6 +295,17 @@ class ReportLib(object): """ Show frames of internal methods of the Java interpreter. """ self._ShowArtFramesFunc(self.getInstance(), show) + def MergeJavaMethods(self, merge=True): + """ This option merges jitted java methods with the same name but in different jit + symfiles. If possible, it also merges jitted methods with interpreted methods, + by mapping jitted methods to their corresponding dex files. + Side effects: + It only works at method level, not instruction level. + It makes symbol.vaddr_in_file and symbol.mapping not accurate for jitted methods. + Java methods are merged by default. + """ + self._MergeJavaMethodsFunc(self.getInstance(), merge) + def SetKallsymsFile(self, kallsym_file): """ Set the file path to a copy of the /proc/kallsyms file (for off device decoding) """ cond = self._SetKallsymsFileFunc(self.getInstance(), _char_pt(kallsym_file)) diff --git a/simpleperf/scripts/test.py b/simpleperf/scripts/test.py index e5b5957b..2adee0e0 100755 --- a/simpleperf/scripts/test.py +++ b/simpleperf/scripts/test.py @@ -990,6 +990,31 @@ class TestReportLib(unittest.TestCase): report_lib.ShowArtFrames(True) self.assertTrue(has_art_frame(report_lib)) + def test_merge_java_methods(self): + def parse_dso_names(report_lib): + dso_names = set() + report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_interpreter_frames.data')) + while report_lib.GetNextSample(): + dso_names.add(report_lib.GetSymbolOfCurrentSample().dso_name) + callchain = report_lib.GetCallChainOfCurrentSample() + for i in range(callchain.nr): + dso_names.add(callchain.entries[i].symbol.dso_name) + report_lib.Close() + has_jit_symfiles = any('TemporaryFile-' in name for name in dso_names) + has_jit_cache = '[JIT cache]' in dso_names + return has_jit_symfiles, has_jit_cache + + report_lib = ReportLib() + self.assertEqual(parse_dso_names(report_lib), (False, True)) + + report_lib = ReportLib() + report_lib.MergeJavaMethods(True) + self.assertEqual(parse_dso_names(report_lib), (False, True)) + + report_lib = ReportLib() + report_lib.MergeJavaMethods(False) + self.assertEqual(parse_dso_names(report_lib), (True, False)) + def test_tracing_data(self): self.report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_tracepoint_event.data')) has_tracing_data = False |