diff options
author | Yabin Cui <yabinc@google.com> | 2021-12-22 11:45:30 -0800 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2021-12-22 13:39:39 -0800 |
commit | 32b962795f47b97614242febbb37e939beeb20c7 (patch) | |
tree | fd09e510d2d6f8f49610eae6ef3d2c81e8946fbf | |
parent | 69bfaa797822101a20b0059b0a5e390aa88d4dbb (diff) | |
download | extras-32b962795f47b97614242febbb37e939beeb20c7.tar.gz |
simpleperf: add --print-event-count in report cmd.
--print-event-count is used to print event counts associated
with each sample. The event counts can be added by --add-counter
in record cmd.
Bug: 211001574
Test: run simpleperf_unit_test
Change-Id: I93f0760de0a8b10bb9ca4fa3dc4c71c0a2e80624
-rw-r--r-- | simpleperf/cmd_report.cpp | 102 | ||||
-rw-r--r-- | simpleperf/cmd_report_test.cpp | 33 | ||||
-rw-r--r-- | simpleperf/event_attr.h | 2 | ||||
-rw-r--r-- | simpleperf/event_selection_set.cpp | 2 | ||||
-rw-r--r-- | simpleperf/testdata/perf_with_add_counter.data | bin | 0 -> 15685 bytes |
5 files changed, 105 insertions, 34 deletions
diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp index 96ee9276..e9b09dfd 100644 --- a/simpleperf/cmd_report.cpp +++ b/simpleperf/cmd_report.cpp @@ -409,11 +409,6 @@ class ReportCmdCallgraphDisplayerWithVaddrInFile : public ReportCmdCallgraphDisp } }; -struct EventAttrWithName { - perf_event_attr attr; - std::string name; -}; - class ReportCommand : public Command { public: ReportCommand() @@ -447,6 +442,8 @@ class ReportCommand : public Command { "-o report_file_name Set report file name, default is stdout.\n" "--percent-limit <percent> Set min percentage in report entries and call graphs.\n" "--pids pid1,pid2,... Report only for selected pids.\n" +"--print-event-count Print event counts for each item. Additional events can be added by\n" +" --add-counter in record cmd.\n" "--raw-period Report period count instead of period percentage.\n" "--sort key1,key2,... Select keys used to group samples into report entries. Samples having\n" " the same key values are aggregated into one report entry. Each report\n" @@ -490,8 +487,7 @@ class ReportCommand : public Command { private: bool ParseOptions(const std::vector<std::string>& args); - bool BuildSampleComparatorAndDisplayer(bool print_sample_count, - const std::vector<std::string>& sort_keys); + bool BuildSampleComparatorAndDisplayer(); void ReadMetaInfoFromRecordFile(); bool ReadEventAttrFromRecordFile(); bool ReadFeaturesFromRecordFile(); @@ -505,7 +501,8 @@ class ReportCommand : public Command { std::string record_filename_; ArchType record_file_arch_; std::unique_ptr<RecordFileReader> record_file_reader_; - std::vector<EventAttrWithName> event_attrs_; + std::vector<perf_event_attr> event_attrs_; + std::vector<std::string> attr_names_; ThreadTree thread_tree_; // Create a SampleTreeBuilder and SampleTree for each event_attr. std::vector<SampleTree> sample_tree_; @@ -527,7 +524,9 @@ class ReportCommand : public Command { size_t sched_switch_attr_id_; bool report_csv_ = false; std::string csv_separator_ = ","; - + bool print_sample_count_ = false; + bool print_event_count_ = false; + std::vector<std::string> sort_keys_; std::string report_filename_; }; @@ -546,6 +545,9 @@ bool ReportCommand::Run(const std::vector<std::string>& args) { if (!ReadEventAttrFromRecordFile()) { return false; } + if (!BuildSampleComparatorAndDisplayer()) { + return false; + } // Read features first to prepare build ids used when building SampleTree. if (!ReadFeaturesFromRecordFile()) { return false; @@ -583,6 +585,7 @@ bool ReportCommand::ParseOptions(const std::vector<std::string>& args) { {"-o", {OptionValueType::STRING, OptionType::SINGLE}}, {"--percent-limit", {OptionValueType::DOUBLE, OptionType::SINGLE}}, {"--pids", {OptionValueType::STRING, OptionType::MULTIPLE}}, + {"--print-event-count", {OptionValueType::NONE, OptionType::SINGLE}}, {"--tids", {OptionValueType::STRING, OptionType::MULTIPLE}}, {"--raw-period", {OptionValueType::NONE, OptionType::SINGLE}}, {"--sort", {OptionValueType::STRING, OptionType::SINGLE}}, @@ -645,7 +648,7 @@ bool ReportCommand::ParseOptions(const std::vector<std::string>& args) { if (!options.PullUintValue("--max-stack", &callgraph_max_stack_)) { return false; } - bool print_sample_count = options.PullBoolValue("-n"); + print_sample_count_ = options.PullBoolValue("-n"); Dso::SetDemangle(!options.PullBoolValue("--no-demangle")); @@ -665,6 +668,7 @@ bool ReportCommand::ParseOptions(const std::vector<std::string>& args) { return false; } } + print_event_count_ = options.PullBoolValue("--print-event-count"); for (const OptionValue& value : options.PullValues("--tids")) { if (auto tids = GetTidsFromString(*value.str_value, false); tids) { sample_tree_builder_options_.tid_filter.insert(tids->begin(), tids->end()); @@ -674,9 +678,9 @@ bool ReportCommand::ParseOptions(const std::vector<std::string>& args) { } raw_period_ = options.PullBoolValue("--raw-period"); - std::vector<std::string> sort_keys = {"comm", "pid", "tid", "dso", "symbol"}; + sort_keys_ = {"comm", "pid", "tid", "dso", "symbol"}; if (auto value = options.PullValue("--sort"); value) { - sort_keys = Split(*value->str_value, ","); + sort_keys_ = Split(*value->str_value, ","); } for (const OptionValue& value : options.PullValues("--symbols")) { @@ -693,11 +697,10 @@ bool ReportCommand::ParseOptions(const std::vector<std::string>& args) { Dso::SetVmlinux(*value->str_value); } CHECK(options.values.empty()); - return BuildSampleComparatorAndDisplayer(print_sample_count, sort_keys); + return true; } -bool ReportCommand::BuildSampleComparatorAndDisplayer(bool print_sample_count, - const std::vector<std::string>& sort_keys) { +bool ReportCommand::BuildSampleComparatorAndDisplayer() { SampleDisplayer<SampleEntry, SampleTree> displayer; displayer.SetReportFormat(report_csv_, csv_separator_); SampleComparator<SampleEntry> comparator; @@ -717,11 +720,38 @@ bool ReportCommand::BuildSampleComparatorAndDisplayer(bool print_sample_count, displayer.AddDisplayFunction("Overhead", DisplaySelfOverhead<SampleEntry, SampleTree>); } } - if (print_sample_count) { + if (print_sample_count_) { displayer.AddDisplayFunction("Sample", DisplaySampleCount<SampleEntry>); } + if (print_event_count_) { + if (event_attrs_.size() == attr_names_.size()) { + // Without additional counters, counts field isn't available. So print period field instead. + if (accumulate_callchain_) { + displayer.AddDisplayFunction("AccEventCount", DisplayAccumulatedPeriod<SampleEntry>); + displayer.AddDisplayFunction("SelfEventCount", DisplaySelfPeriod<SampleEntry>); + } else { + displayer.AddDisplayFunction("EventCount", DisplaySelfPeriod<SampleEntry>); + } + } else { + // With additional counters, print counts field. + for (size_t i = 0; i < attr_names_.size(); i++) { + auto self_event_count_fn = [i](const SampleEntry* s) { + return i < s->counts.size() ? std::to_string(s->counts[i]) : "0"; + }; + auto acc_event_count_fn = [i](const SampleEntry* s) { + return i < s->acc_counts.size() ? std::to_string(s->acc_counts[i]) : "0"; + }; + if (accumulate_callchain_) { + displayer.AddDisplayFunction("AccEventCount_" + attr_names_[i], acc_event_count_fn); + displayer.AddDisplayFunction("SelfEventCount_" + attr_names_[i], self_event_count_fn); + } else { + displayer.AddDisplayFunction("EventCount_" + attr_names_[i], self_event_count_fn); + } + } + } + } - for (auto& key : sort_keys) { + for (auto& key : sort_keys_) { if (!use_branch_address_ && branch_sort_keys.find(key) != branch_sort_keys.end()) { LOG(ERROR) << "sort key '" << key << "' can only be used with -b option."; return false; @@ -762,7 +792,9 @@ bool ReportCommand::BuildSampleComparatorAndDisplayer(bool print_sample_count, } } - if (report_csv_) { + // Reporting with --csv will add event count and event name columns. But if --print-event-count is + // used, there is no need to duplicate printing event counts. + if (report_csv_ && !print_event_count_) { if (accumulate_callchain_) { displayer.AddDisplayFunction("AccEventCount", DisplayAccumulatedPeriod<SampleEntry>); displayer.AddDisplayFunction("SelfEventCount", DisplaySelfPeriod<SampleEntry>); @@ -775,7 +807,7 @@ bool ReportCommand::BuildSampleComparatorAndDisplayer(bool print_sample_count, if (print_callgraph_) { bool has_symbol_key = false; bool has_vaddr_in_file_key = false; - for (const auto& key : sort_keys) { + for (const auto& key : sort_keys_) { if (key == "symbol") { has_symbol_key = true; } else if (key == "vaddr_in_file") { @@ -824,15 +856,20 @@ void ReportCommand::ReadMetaInfoFromRecordFile() { bool ReportCommand::ReadEventAttrFromRecordFile() { std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection(); for (const auto& attr_with_id : attrs) { - EventAttrWithName attr; - attr.attr = *attr_with_id.attr; - attr.name = GetEventNameByAttr(attr.attr); - event_attrs_.push_back(attr); + const perf_event_attr& attr = *attr_with_id.attr; + attr_names_.emplace_back(GetEventNameByAttr(attr)); + + // There are no samples for events added by --add-counter. So skip them. + if ((attr.read_format & PERF_FORMAT_GROUP) && (attr.freq == 0) && + (attr.sample_period == INFINITE_SAMPLE_PERIOD)) { + continue; + } + event_attrs_.emplace_back(attr); } if (use_branch_address_) { bool has_branch_stack = true; for (const auto& attr : event_attrs_) { - if ((attr.attr.sample_type & PERF_SAMPLE_BRANCH_STACK) == 0) { + if ((attr.sample_type & PERF_SAMPLE_BRANCH_STACK) == 0) { has_branch_stack = false; break; } @@ -845,7 +882,7 @@ bool ReportCommand::ReadEventAttrFromRecordFile() { if (trace_offcpu_) { size_t i; for (i = 0; i < event_attrs_.size(); ++i) { - if (event_attrs_[i].name == "sched:sched_switch") { + if (attr_names_[i] == "sched:sched_switch") { break; } } @@ -893,7 +930,7 @@ bool ReportCommand::ReadSampleTreeFromRecordFile() { for (size_t i = 0; i < event_attrs_.size(); ++i) { sample_tree_builder_.push_back( sample_tree_builder_options_.CreateSampleTreeBuilder(*record_file_reader_)); - sample_tree_builder_.back()->SetEventName(event_attrs_[i].name); + sample_tree_builder_.back()->SetEventName(attr_names_[i]); OfflineUnwinder* unwinder = sample_tree_builder_.back()->GetUnwinder(); if (unwinder != nullptr) { unwinder->LoadMetaInfo(record_file_reader_->GetMetaInfoFeature()); @@ -950,10 +987,10 @@ void ReportCommand::ProcessSampleRecordInTraceOffCpuMode(std::unique_ptr<Record> bool ReportCommand::ProcessTracingData(const std::vector<char>& data) { Tracing tracing(data); - for (auto& attr : event_attrs_) { - if (attr.attr.type == PERF_TYPE_TRACEPOINT) { - uint64_t trace_event_id = attr.attr.config; - attr.name = tracing.GetTracingEventNameHavingId(trace_event_id); + for (size_t i = 0; i < event_attrs_.size(); i++) { + if (event_attrs_[i].type == PERF_TYPE_TRACEPOINT) { + uint64_t trace_event_id = event_attrs_[i].config; + attr_names_[i] = tracing.GetTracingEventNameHavingId(trace_event_id); } } return true; @@ -978,10 +1015,9 @@ bool ReportCommand::PrintReport() { if (i != 0) { fprintf(report_fp, "\n"); } - EventAttrWithName& attr = event_attrs_[i]; SampleTree& sample_tree = sample_tree_[i]; - fprintf(report_fp, "Event: %s (type %u, config %llu)\n", attr.name.c_str(), attr.attr.type, - attr.attr.config); + fprintf(report_fp, "Event: %s (type %u, config %llu)\n", attr_names_[i].c_str(), + event_attrs_[i].type, event_attrs_[i].config); fprintf(report_fp, "Samples: %" PRIu64 "\n", sample_tree.total_samples); if (sample_tree.total_error_callchains != 0) { fprintf(report_fp, "Error Callchains: %" PRIu64 ", %f%%\n", diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp index e7ce9c44..5104e8c7 100644 --- a/simpleperf/cmd_report_test.cpp +++ b/simpleperf/cmd_report_test.cpp @@ -564,6 +564,39 @@ TEST_F(ReportCommandTest, cpu_option) { ASSERT_FALSE(ReportCmd()->Run({"-i", GetTestData("perf.data"), "--cpu", "-2"})); } +TEST_F(ReportCommandTest, print_event_count_option) { + // Report record file not recorded with --add-counter. + Report("perf.data", {"--print-event-count"}); + ASSERT_TRUE(success); + ASSERT_NE(content.find("EventCount"), std::string::npos); + ASSERT_TRUE(std::regex_search( + content, std::regex(R"(325005586\s+elf\s+26083\s+26083\s+/elf\s+GlobalFunc)"))); + + // Report record file recorded with --add-counter. + const std::string record_file = "perf_with_add_counter.data"; + Report(record_file, {"--print-event-count"}); + ASSERT_TRUE(success); + ASSERT_TRUE( + std::regex_search(content, std::regex(R"(EventCount_cpu-cycles\s+EventCount_instructions)"))); + ASSERT_TRUE(std::regex_search( + content, std::regex(R"(175099\s+140443\s+sleep\s+689664\s+689664.+_dl_addr)"))); + + // Report accumulated event counts. + Report(record_file, {"--print-event-count", "--children"}); + ASSERT_TRUE(success); + ASSERT_TRUE(std::regex_search( + content, + std::regex( + R"(AccEventCount_cpu-cycles\s+SelfEventCount_cpu-cycles\s+AccEventCount_instructions\s+)" + R"(SelfEventCount_instructions)"))); + ASSERT_TRUE(std::regex_search( + content, + std::regex(R"(175099\s+175099\s+140443\s+140443\s+sleep\s+689664\s+689664.+_dl_addr)"))); + ASSERT_TRUE(std::regex_search( + content, + std::regex(R"(366116\s+0\s+297474\s+0\s+sleep\s+689664\s+689664.+__libc_start_main)"))); +} + #if defined(__linux__) #include "event_selection_set.h" diff --git a/simpleperf/event_attr.h b/simpleperf/event_attr.h index 9957bf7c..a9d8bba7 100644 --- a/simpleperf/event_attr.h +++ b/simpleperf/event_attr.h @@ -33,6 +33,8 @@ struct EventAttrWithId { std::vector<uint64_t> ids; }; +inline constexpr uint64_t INFINITE_SAMPLE_PERIOD = 1ULL << 62; + perf_event_attr CreateDefaultPerfEventAttr(const EventType& event_type); void DumpPerfEventAttr(const perf_event_attr& attr, size_t indent = 0); bool GetCommonEventIdPositionsForAttrs(std::vector<perf_event_attr>& attrs, diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp index 6d0c1625..a6d9a7e0 100644 --- a/simpleperf/event_selection_set.cpp +++ b/simpleperf/event_selection_set.cpp @@ -321,7 +321,7 @@ bool EventSelectionSet::AddCounters(const std::vector<std::string>& event_names) } // Use a big sample_period to avoid getting samples for added counters. selection.event_attr.freq = 0; - selection.event_attr.sample_period = 1ULL << 62; + selection.event_attr.sample_period = INFINITE_SAMPLE_PERIOD; selection.event_attr.inherit = 0; groups_[0].emplace_back(std::move(selection)); } diff --git a/simpleperf/testdata/perf_with_add_counter.data b/simpleperf/testdata/perf_with_add_counter.data Binary files differnew file mode 100644 index 00000000..cd9347f3 --- /dev/null +++ b/simpleperf/testdata/perf_with_add_counter.data |