summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2019-10-08 23:10:18 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2019-10-08 23:10:18 +0000
commitbf9f91a149664b1e30ddababa8b44abf8af66b6c (patch)
tree64482124ee0e52ffe9d0b8a743d3086209435f34
parentc5f7c38480a268da19b43dfa52914822c5e091d1 (diff)
parent76554a4e55c760595abd6857d846193f60252863 (diff)
downloadextras-bf9f91a149664b1e30ddababa8b44abf8af66b6c.tar.gz
Merge "simpleperf: merge jitted and interpreted java methods."
-rw-r--r--simpleperf/report_lib_interface.cpp35
-rw-r--r--simpleperf/scripts/simpleperf_report_lib.py12
-rwxr-xr-xsimpleperf/scripts/test.py25
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 &current_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