summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2021-12-21 10:41:31 -0800
committerYabin Cui <yabinc@google.com>2021-12-21 11:01:25 -0800
commit5a6ed905d92bae7085f2b2b4f7c178ea873e8994 (patch)
treebe922cc9075cbb1f075454afe7949514a8da52a6
parentd6b4b44bad078fb647d01b13a2f39b9ddcaa61b3 (diff)
downloadextras-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.cpp18
-rw-r--r--simpleperf/cmd_record_impl.h1
-rw-r--r--simpleperf/cmd_record_test.cpp21
-rw-r--r--simpleperf/event_selection_set.cpp25
-rw-r--r--simpleperf/event_selection_set.h2
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;