diff options
author | Yabin Cui <yabinc@google.com> | 2018-02-06 17:49:06 -0800 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2018-02-08 12:04:23 -0800 |
commit | 46848c6da4eff8ea368c3972ee959b994e5dd55d (patch) | |
tree | d455ade9e0a3d75ba41b959b784b87e8e6ebc988 | |
parent | 329daa8b39041fb2041a52aa35dd945b39e870f2 (diff) | |
download | extras-46848c6da4eff8ea368c3972ee959b994e5dd55d.tar.gz |
simpleperf: improve debug-unwind cmd.
In debug-unwind cmd:
1. Add --symfs option.
2. Add meta_info section when there isn't one.
3. Add file section when there isn't one.
Rename unwinding_result_reporter.py to debug_unwind_reporter.py,
and fix a small error in it.
Bug: http://b/72556486
Test: run simpleperf_unit_test.
Test: run debug_unwind_reporter.py manually.
Change-Id: Ibc66b7bfdc91a17f6f1c2c0e84f4769d2bcaa1e7
-rw-r--r-- | simpleperf/cmd_debug_unwind.cpp | 71 | ||||
-rw-r--r-- | simpleperf/cmd_debug_unwind_test.cpp | 24 | ||||
-rw-r--r-- | simpleperf/scripts/debug_unwind_reporter.py (renamed from simpleperf/scripts/unwinding_result_reporter.py) | 12 |
3 files changed, 77 insertions, 30 deletions
diff --git a/simpleperf/cmd_debug_unwind.cpp b/simpleperf/cmd_debug_unwind.cpp index d356355c..cd96a759 100644 --- a/simpleperf/cmd_debug_unwind.cpp +++ b/simpleperf/cmd_debug_unwind.cpp @@ -88,6 +88,7 @@ class DebugUnwindCommand : public Command { "-i <file> The path of record file generated with \"-g --no-unwind\".\n" " Default is perf.data.\n" "-o <file> The path ot write new perf.data. Default is perf.data.debug.\n" +"--symfs <dir> Look for files with symbols relative to this directory.\n" "--time time Only unwind samples recorded at selected time.\n" // clang-format on ), @@ -159,6 +160,13 @@ bool DebugUnwindCommand::ParseOptions(const std::vector<std::string>& args) { return false; } output_filename_ = args[i]; + } else if (args[i] == "--symfs") { + if (!NextArgumentOrError(args, &i)) { + return false; + } + if (!Dso::SetSymFsDir(args[i])) { + return false; + } } else if (args[i] == "--time") { if (!NextArgumentOrError(args, &i)) { return false; @@ -339,34 +347,49 @@ bool DebugUnwindCommand::JoinCallChains() { } bool DebugUnwindCommand::WriteFeatureSections() { + // Add debug_unwind info in META_INFO section, and add symbol info in FILE section. const std::map<int, PerfFileFormat::SectionDesc>& features = reader_->FeatureSectionDescriptors(); - if (!writer_->BeginWriteFeatures(features.size())) { + size_t new_feature_count = features.size(); + for (int feature : {PerfFileFormat::FEAT_FILE, PerfFileFormat::FEAT_META_INFO}) { + if (features.find(feature) == features.end()) { + new_feature_count++; + } + } + if (!writer_->BeginWriteFeatures(new_feature_count)) { return false; } - for (auto& pair : features) { - int feature = pair.first; - if (feature == PerfFileFormat::FEAT_META_INFO) { - std::unordered_map<std::string, std::string> info_map; - if (!reader_->ReadMetaInfoFeature(&info_map)) { - return false; - } - info_map["debug_unwind"] = "true"; - info_map["debug_unwind_mem_before"] = stat_.mem_before_unwinding.ToString(); - info_map["debug_unwind_mem_after"] = stat_.mem_after_unwinding.ToString(); - if (!writer_->WriteMetaInfoFeature(info_map)) { - return false; - } - } else if (feature == PerfFileFormat::FEAT_FILE) { - if (!writer_->WriteFileFeatures(thread_tree_.GetAllDsos())) { - return false; - } - } else { - std::vector<char> data; - if (!reader_->ReadFeatureSection(feature, &data) || !writer_->WriteFeature(feature, data)) { - return false; - } + + auto it = features.begin(); + // Copy all feature sections except FEAT_FILE and FEAT_META_INFO, which require special handling. + while (it != features.end() && it->first < PerfFileFormat::FEAT_FILE) { + std::vector<char> data; + if (!reader_->ReadFeatureSection(it->first, &data) || !writer_->WriteFeature(it->first, data)) { + return false; } + ++it; + } + // Write a new file section. + if (it != features.end() && it->first == PerfFileFormat::FEAT_FILE) { + ++it; + } + if (!writer_->WriteFileFeatures(thread_tree_.GetAllDsos())) { + return false; + } + // Write meta_info section. + std::unordered_map<std::string, std::string> info_map; + if (it != features.end() && it->first == PerfFileFormat::FEAT_META_INFO) { + if (!reader_->ReadMetaInfoFeature(&info_map)) { + return false; + } + ++it; + } + info_map["debug_unwind"] = "true"; + info_map["debug_unwind_mem_before"] = stat_.mem_before_unwinding.ToString(); + info_map["debug_unwind_mem_after"] = stat_.mem_after_unwinding.ToString(); + if (!writer_->WriteMetaInfoFeature(info_map)) { + return false; } + CHECK(it == features.end()); return writer_->EndWriteFeatures() && writer_->Close(); } @@ -388,7 +411,7 @@ void DebugUnwindCommand::PrintStat() { PrintIndented(1, "VmRSS: %s -> %s\n", stat_.mem_before_unwinding.vm_rss.c_str(), stat_.mem_after_unwinding.vm_rss.c_str()); callchain_joiner_.DumpStat(); - printf("Please use unwinding_result_reporter.py to get a report in details.\n"); + printf("Please use debug_unwind_reporter.py to get a report in details.\n"); } void RegisterDebugUnwindCommand() { diff --git a/simpleperf/cmd_debug_unwind_test.cpp b/simpleperf/cmd_debug_unwind_test.cpp index bae45f6b..e6d44318 100644 --- a/simpleperf/cmd_debug_unwind_test.cpp +++ b/simpleperf/cmd_debug_unwind_test.cpp @@ -27,6 +27,7 @@ #include "command.h" #include "get_test_data.h" +#include "record_file.h" #include "test_util.h" #if defined(__aarch64__) @@ -93,3 +94,26 @@ TEST(cmd_debug_unwind, smoke) { GTEST_LOG_(INFO) << "This test does nothing on non-ARM64 devices."; #endif } + +TEST(cmd_debug_unwind, symfs_option) { + // TODO: Remove the arch limitation once using cross-platform unwinding in the new unwinder. +#if defined(__aarch64__) + std::string input_data = GetTestData(NATIVELIB_IN_APK_PERF_DATA); + CaptureStdout capture; + TemporaryFile tmp_file; + ASSERT_TRUE(capture.Start()); + ASSERT_TRUE(DebugUnwindCmd()->Run({"-i", input_data, "-o", tmp_file.path, "--symfs", + GetTestDataDir()})); + ASSERT_NE(capture.Finish().find("Unwinding sample count: 55"), std::string::npos); + std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmp_file.path); + ASSERT_TRUE(reader); + const std::map<int, PerfFileFormat::SectionDesc>& features = reader->FeatureSectionDescriptors(); + ASSERT_NE(features.find(PerfFileFormat::FEAT_FILE), features.end()); + ASSERT_NE(features.find(PerfFileFormat::FEAT_META_INFO), features.end()); + std::unordered_map<std::string, std::string> info_map; + ASSERT_TRUE(reader->ReadMetaInfoFeature(&info_map)); + ASSERT_EQ(info_map["debug_unwind"], "true"); +#else + GTEST_LOG_(INFO) << "This test does nothing on non-ARM64 devices."; +#endif +} diff --git a/simpleperf/scripts/unwinding_result_reporter.py b/simpleperf/scripts/debug_unwind_reporter.py index 3eee00a6..56b51760 100644 --- a/simpleperf/scripts/unwinding_result_reporter.py +++ b/simpleperf/scripts/debug_unwind_reporter.py @@ -15,14 +15,14 @@ # limitations under the License. # -"""unwinding_result_reporter.py: report dwarf unwinding results generated by debug-unwind cmd. - Below is an example using unwinding_result_reporter.py: +"""debug_unwind_reporter.py: report dwarf unwinding results generated by debug-unwind cmd. + Below is an example using debug_unwind_reporter.py: 1. Record with "-g --no-unwind" option on device. simpleperf record -g --no-unwind --app com.google.sample.tunnel --duration 10 2. Use debug-unwind cmd to unwind samples in perf.data on device. simpleperf debug-unwind 3. Pull perf.data.debug on host, and report it with this script. - python unwinding_result_reporter.py + python debug_unwind_reporter.py It reports below items: 1. time used for offline dwarf unwinding for each sample. @@ -380,8 +380,8 @@ def build_unwinding_result_report(args): stdout=subprocess.PIPE) (stdoutdata, _) = proc.communicate() if 'debug_unwind = true' not in stdoutdata: - log_exit("Can't parse unwinding result. Because %s is not generated by debug-unwind cmd." - % record_file) + log_exit("Can't parse unwinding result. Because " + + "%s was not generated by the debug-unwind cmd." % args.record_file[0]) unwinding_report = UnwindingResultErrorReport(args.omit_callchains_fixed_by_joiner) process_maps = unwinding_report.process_maps lines = stdoutdata.split('\n') @@ -454,7 +454,7 @@ def build_unwinding_result_report(args): def main(): parser = argparse.ArgumentParser( - description='report dwarf unwinding results generated by debug-unwind cmd') + description='Report dwarf unwinding results generated by the debug-unwind cmd.') parser.add_argument('-i', '--record_file', nargs=1, default=['perf.data.debug'], help=""" Set profiling data to report. Default is perf.data.debug.""") parser.add_argument('--omit-callchains-fixed-by-joiner', action='store_true', help=""" |