summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2021-12-22 11:45:30 -0800
committerYabin Cui <yabinc@google.com>2021-12-22 13:39:39 -0800
commit32b962795f47b97614242febbb37e939beeb20c7 (patch)
treefd09e510d2d6f8f49610eae6ef3d2c81e8946fbf
parent69bfaa797822101a20b0059b0a5e390aa88d4dbb (diff)
downloadextras-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.cpp102
-rw-r--r--simpleperf/cmd_report_test.cpp33
-rw-r--r--simpleperf/event_attr.h2
-rw-r--r--simpleperf/event_selection_set.cpp2
-rw-r--r--simpleperf/testdata/perf_with_add_counter.databin0 -> 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
new file mode 100644
index 00000000..cd9347f3
--- /dev/null
+++ b/simpleperf/testdata/perf_with_add_counter.data
Binary files differ