diff options
author | Yabin Cui <yabinc@google.com> | 2018-03-26 17:34:00 -0700 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2018-03-28 17:16:27 -0700 |
commit | 516a87cd05e6f7dcf2c45fd8ba6d1d0e1e1e7bdd (patch) | |
tree | 642ab8433692d1862900ac93c7a24fc131ef4822 /simpleperf/cmd_record.cpp | |
parent | 81ed0ea0e64d536287e823431f4999f183cc3cf1 (diff) | |
download | extras-516a87cd05e6f7dcf2c45fd8ba6d1d0e1e1e7bdd.tar.gz |
simpleperf: support showing symbols for interpreted java code.
To convert from a dex_pc (returned by libunwindstack) to a symbol name,
we need below things:
1. The mapping info of the vdex file containing the dex_pc.
2. The offsets of dex files in the vdex file.
So make below changes:
1. Record none executable maps when profiling java code.
2. Refactor dso code to add a new type for dex file, using DexFileDso
to store dex file offsets in a vdex file, and load symbols from that
vdex file.
3. Add read_dex_file.cpp to read java symbols using libdexfile.
4. Change the format of file section in record_file_format.h, to store
dex file offsets in vdex files.
Bug: http://b/73126888
Bug: http://b/77236599
Test: Run simpleperf to profile several apps manually, can see
Test: callstacks of both java code and native code.
Test: Run simpleperf_unit_test.
Change-Id: I08005a03beb3df1a70db034bc463f555934856ba
Diffstat (limited to 'simpleperf/cmd_record.cpp')
-rw-r--r-- | simpleperf/cmd_record.cpp | 63 |
1 files changed, 47 insertions, 16 deletions
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp index 6b7ce94d..5ea42573 100644 --- a/simpleperf/cmd_record.cpp +++ b/simpleperf/cmd_record.cpp @@ -252,6 +252,7 @@ class RecordCommand : public Command { bool DumpKernelAndModuleMmaps(const perf_event_attr& attr, uint64_t event_id); bool DumpThreadCommAndMmaps(const perf_event_attr& attr, uint64_t event_id); bool ProcessRecord(Record* record); + bool ShouldOmitRecord(Record* record); bool SaveRecordForPostUnwinding(Record* record); bool SaveRecordAfterUnwinding(Record* record); bool SaveRecordWithoutUnwinding(Record* record); @@ -415,6 +416,16 @@ bool RecordCommand::PrepareRecording(Workload* workload) { } else { need_to_check_targets = true; } + // Profiling JITed/interpreted Java code is supported starting from Android P. + if (app_pid != 0 && GetAndroidVersion() >= kAndroidVersionP) { + // JIT symfiles are stored in temporary files, and are deleted after recording. But if + // `-g --no-unwind` option is used, we want to keep symfiles to support unwinding in + // the debug-unwind cmd. + bool keep_symfiles = dwarf_callchain_sampling_ && !unwind_dwarf_callchain_; + jit_debug_reader_.reset(new JITDebugReader(app_pid, keep_symfiles)); + // To profile java code, need to dump maps containing vdex files, which are not executable. + event_selection_set_.SetRecordNotExecutableMaps(true); + } // 5. Open perf event files and create mapped buffers. if (!event_selection_set_.OpenEventFiles(cpus_)) { @@ -458,14 +469,7 @@ bool RecordCommand::PrepareRecording(Workload* workload) { return false; } } - // Profiling JITed/interpreted code is supported starting from Android P. - const int kAndroidVersionP = 9; - if (app_pid != 0 && GetAndroidVersion() >= kAndroidVersionP) { - // JIT symfiles are stored in temporary files, and are deleted after recording. But if - // `-g --no-unwind` option is used, we want to keep symfiles to support unwinding in - // the debug-unwind cmd. - bool keep_symfiles = dwarf_callchain_sampling_ && !unwind_dwarf_callchain_; - jit_debug_reader_.reset(new JITDebugReader(app_pid, keep_symfiles)); + if (jit_debug_reader_) { // Update JIT info at the beginning of recording. if (!UpdateJITDebugInfo()) { return false; @@ -1006,8 +1010,8 @@ bool RecordCommand::DumpThreadCommAndMmaps(const perf_event_attr& attr, continue; } for (const auto& map : thread_mmaps) { - if (map.executable == 0) { - continue; // No need to dump non-executable mmap info. + if (map.executable == 0 && !event_selection_set_.RecordNotExecutableMaps()) { + continue; } MmapRecord record(attr, false, pid, pid, map.start_addr, map.len, map.pgoff, map.name, event_id); @@ -1047,6 +1051,9 @@ bool RecordCommand::DumpThreadCommAndMmaps(const perf_event_attr& attr, } bool RecordCommand::ProcessRecord(Record* record) { + if (ShouldOmitRecord(record)) { + return true; + } last_record_timestamp_ = record->Timestamp(); if (unwind_dwarf_callchain_) { if (post_unwind_) { @@ -1057,7 +1064,32 @@ bool RecordCommand::ProcessRecord(Record* record) { return SaveRecordWithoutUnwinding(record); } +template <typename MmapRecordType> +bool IsMappingOnlyExistInMemory(MmapRecordType* record) { + return !record->InKernel() && !IsRegularFile(record->filename) && record->filename != "[vdso]"; +} + +bool RecordCommand::ShouldOmitRecord(Record* record) { + if (jit_debug_reader_) { + // To profile jitted Java code, we need PROT_JIT_SYMFILE_MAP maps not overlapped by maps for + // /dev/ashmem/dalvik-jit-code-cache. To profile interpreted Java code, we record maps that + // are not executable. Some non-exec maps (like those for stack, heap) provide misleading map + // entries for unwinding, as in http://b/77236599. So it is better to remove + // dalvik-jit-code-cache and other maps that only exist in memory. + switch (record->type()) { + case PERF_RECORD_MMAP: + return IsMappingOnlyExistInMemory(static_cast<MmapRecord*>(record)); + case PERF_RECORD_MMAP2: + return IsMappingOnlyExistInMemory(static_cast<Mmap2Record*>(record)); + } + } + return false; +} + bool RecordCommand::SaveRecordForPostUnwinding(Record* record) { + if (ShouldOmitRecord(record)) { + return true; + } if (record->type() == PERF_RECORD_SAMPLE) { static_cast<SampleRecord*>(record)->RemoveInvalidStackData(); } @@ -1131,7 +1163,9 @@ bool RecordCommand::UpdateJITDebugInfo() { return false; } } - // TODO: Handle dex symfiles. + for (auto& symfile : dex_symfiles) { + thread_tree_.AddDexFileOffset(symfile.file_path, symfile.dex_file_offset); + } return true; } @@ -1285,20 +1319,17 @@ bool RecordCommand::DumpAdditionalFeatures( return false; } - size_t feature_count = 5; + size_t feature_count = 6; if (branch_sampling_) { feature_count++; } - if (dump_symbols_) { - feature_count++; - } if (!record_file_writer_->BeginWriteFeatures(feature_count)) { return false; } if (!DumpBuildIdFeature()) { return false; } - if (dump_symbols_ && !DumpFileFeature()) { + if (!DumpFileFeature()) { return false; } utsname uname_buf; |