summaryrefslogtreecommitdiff
path: root/simpleperf/cmd_record.cpp
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2018-03-26 17:34:00 -0700
committerYabin Cui <yabinc@google.com>2018-03-28 17:16:27 -0700
commit516a87cd05e6f7dcf2c45fd8ba6d1d0e1e1e7bdd (patch)
tree642ab8433692d1862900ac93c7a24fc131ef4822 /simpleperf/cmd_record.cpp
parent81ed0ea0e64d536287e823431f4999f183cc3cf1 (diff)
downloadextras-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.cpp63
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;