diff options
author | Yabin Cui <yabinc@google.com> | 2021-12-21 10:41:31 -0800 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2021-12-21 11:01:25 -0800 |
commit | 5a6ed905d92bae7085f2b2b4f7c178ea873e8994 (patch) | |
tree | be922cc9075cbb1f075454afe7949514a8da52a6 | |
parent | d6b4b44bad078fb647d01b13a2f39b9ddcaa61b3 (diff) | |
download | extras-5a6ed905d92bae7085f2b2b4f7c178ea873e8994.tar.gz |
simpleperf: add --add-counter in record cmd.
When --add-counter is used, additional event counts are added
when generating each sample.
Bug: 211001523
Test: run simpleperf_unit_test
Change-Id: I8434508e07c9b3a7e288d0fac7bf8838fde077cd
-rw-r--r-- | simpleperf/cmd_record.cpp | 18 | ||||
-rw-r--r-- | simpleperf/cmd_record_impl.h | 1 | ||||
-rw-r--r-- | simpleperf/cmd_record_test.cpp | 21 | ||||
-rw-r--r-- | simpleperf/event_selection_set.cpp | 25 | ||||
-rw-r--r-- | simpleperf/event_selection_set.h | 2 |
5 files changed, 67 insertions, 0 deletions
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp index 54ebe1e2..443e3895 100644 --- a/simpleperf/cmd_record.cpp +++ b/simpleperf/cmd_record.cpp @@ -172,6 +172,10 @@ class RecordCommand : public Command { " Documentation/trace/kprobetrace.rst in the kernel. Examples:\n" " 'p:myprobe do_sys_open $arg2:string' - add event kprobes:myprobe\n" " 'r:myretprobe do_sys_open $retval:s64' - add event kprobes:myretprobe\n" +"--add-counter event1,event2,... Add additional event counts in record samples. For example,\n" +" we can use `-e cpu-cycles --add-counter instructions` to\n" +" get samples for cpu-cycles event, while having instructions\n" +" event count for each sample.\n" "\n" "Select monitoring options:\n" "-f freq Set event sample frequency. It means recording at most [freq]\n" @@ -441,6 +445,7 @@ RECORD_FILTER_OPTION_HELP_MSG std::unordered_map<std::string, std::string> extra_meta_info_; bool use_cmd_exit_code_ = false; + std::vector<std::string> add_counters_; }; void RecordCommand::Run(const std::vector<std::string>& args, int* exit_code) { @@ -539,6 +544,15 @@ bool RecordCommand::PrepareRecording(Workload* workload) { if (trace_offcpu_ && !TraceOffCpu()) { return false; } + if (!add_counters_.empty()) { + if (child_inherit_) { + LOG(ERROR) << "--no-inherit is needed when using --add-counter."; + return false; + } + if (!event_selection_set_.AddCounters(add_counters_)) { + return false; + } + } if (!SetEventSelectionFlags()) { return false; } @@ -829,6 +843,10 @@ bool RecordCommand::ParseOptions(const std::vector<std::string>& args, // Process options. system_wide_collection_ = options.PullBoolValue("-a"); + if (auto value = options.PullValue("--add-counter"); value) { + add_counters_ = android::base::Split(*value->str_value, ","); + } + for (const OptionValue& value : options.PullValues("--add-meta-info")) { const std::string& s = *value.str_value; auto split_pos = s.find('='); diff --git a/simpleperf/cmd_record_impl.h b/simpleperf/cmd_record_impl.h index 5d685531..0af3c0d8 100644 --- a/simpleperf/cmd_record_impl.h +++ b/simpleperf/cmd_record_impl.h @@ -33,6 +33,7 @@ inline const OptionFormatMap& GetRecordCmdOptionFormats() { if (option_formats.empty()) { option_formats = { {"-a", {OptionValueType::NONE, OptionType::SINGLE, AppRunnerType::NOT_ALLOWED}}, + {"--add-counter", {OptionValueType::STRING, OptionType::SINGLE, AppRunnerType::ALLOWED}}, {"--add-meta-info", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}}, {"--addr-filter", {OptionValueType::STRING, OptionType::SINGLE, AppRunnerType::ALLOWED}}, diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp index d6deacde..f51393f2 100644 --- a/simpleperf/cmd_record_test.cpp +++ b/simpleperf/cmd_record_test.cpp @@ -1208,3 +1208,24 @@ TEST(record_cmd, device_meta_info) { ASSERT_NE(it, meta_info.end()); ASSERT_FALSE(it->second.empty()); } + +TEST(record_cmd, add_counter_option) { + TEST_REQUIRE_HW_COUNTER(); + TemporaryFile tmpfile; + ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles", "--add-counter", "instructions", "--no-inherit", + "-o", tmpfile.path, "sleep", "1"})); + std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path); + ASSERT_TRUE(reader); + bool has_sample = false; + ASSERT_TRUE(reader->ReadDataSection([&](std::unique_ptr<Record> r) { + if (r->type() == PERF_RECORD_SAMPLE) { + has_sample = true; + auto sr = static_cast<SampleRecord*>(r.get()); + if (sr->read_data.counts.size() != 2 || sr->read_data.ids.size() != 2) { + return false; + } + } + return true; + })); + ASSERT_TRUE(has_sample); +} diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp index e7e5afed..6d0c1625 100644 --- a/simpleperf/event_selection_set.cpp +++ b/simpleperf/event_selection_set.cpp @@ -308,6 +308,31 @@ bool EventSelectionSet::AddEventGroup(const std::vector<std::string>& event_name return true; } +bool EventSelectionSet::AddCounters(const std::vector<std::string>& event_names) { + CHECK(!groups_.empty()); + if (groups_.size() > 1) { + LOG(ERROR) << "Failed to add counters. Only one event group is allowed."; + return false; + } + for (const auto& event_name : event_names) { + EventSelection selection; + if (!BuildAndCheckEventSelection(event_name, false, &selection)) { + return false; + } + // 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.inherit = 0; + groups_[0].emplace_back(std::move(selection)); + } + // Add counters in each sample. + for (auto& selection : groups_[0]) { + selection.event_attr.sample_type |= PERF_SAMPLE_READ; + selection.event_attr.read_format |= PERF_FORMAT_GROUP; + } + return true; +} + std::vector<const EventType*> EventSelectionSet::GetEvents() const { std::vector<const EventType*> result; for (const auto& group : groups_) { diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h index 45781edf..07754fd2 100644 --- a/simpleperf/event_selection_set.h +++ b/simpleperf/event_selection_set.h @@ -109,6 +109,8 @@ class EventSelectionSet { bool AddEventType(const std::string& event_name, size_t* group_id = nullptr); bool AddEventGroup(const std::vector<std::string>& event_names, size_t* group_id = nullptr); + // For each sample generated for the existing event group, add counters for selected events. + bool AddCounters(const std::vector<std::string>& event_names); std::vector<const EventType*> GetEvents() const; std::vector<const EventType*> GetTracepointEvents() const; bool ExcludeKernel() const; |