summaryrefslogtreecommitdiff
path: root/simpleperf
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2015-06-19 23:36:25 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-06-19 23:37:00 +0000
commit74d6884c4921e584ce7a775b00eeadac792054aa (patch)
treee1ec58f463c6acc0a451e58caef23568fc1a1f02 /simpleperf
parent60ed78f3cb49e873d0a9aa40d5db33818d0259c2 (diff)
parentd115b2f738f2cef352877b26c2d93460ac9fea25 (diff)
downloadextras-74d6884c4921e584ce7a775b00eeadac792054aa.tar.gz
Merge "Simpleperf: support event type modifier."
Diffstat (limited to 'simpleperf')
-rw-r--r--simpleperf/cmd_list.cpp2
-rw-r--r--simpleperf/cmd_record.cpp32
-rw-r--r--simpleperf/cmd_record_test.cpp4
-rw-r--r--simpleperf/cmd_report.cpp3
-rw-r--r--simpleperf/cmd_stat.cpp26
-rw-r--r--simpleperf/cmd_stat_test.cpp47
-rw-r--r--simpleperf/cpu_offline_test.cpp6
-rw-r--r--simpleperf/event_attr.cpp14
-rw-r--r--simpleperf/event_fd.cpp3
-rw-r--r--simpleperf/event_selection_set.cpp24
-rw-r--r--simpleperf/event_selection_set.h7
-rw-r--r--simpleperf/event_type.cpp88
-rw-r--r--simpleperf/event_type.h30
-rw-r--r--simpleperf/record_file_test.cpp6
-rw-r--r--simpleperf/record_test.cpp6
15 files changed, 205 insertions, 93 deletions
diff --git a/simpleperf/cmd_list.cpp b/simpleperf/cmd_list.cpp
index 338ae266..221f3fb7 100644
--- a/simpleperf/cmd_list.cpp
+++ b/simpleperf/cmd_list.cpp
@@ -71,7 +71,7 @@ bool ListCommand::Run(const std::vector<std::string>& args) {
}
}
- auto& event_types = EventTypeFactory::GetAllEventTypes();
+ auto& event_types = GetAllEventTypes();
for (auto& name : names) {
auto it = type_map.find(name);
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index e87a7ec1..b59dcdc2 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -61,8 +61,12 @@ class RecordCommand : public Command {
" -a System-wide collection.\n"
" -b Enable take branch stack sampling. Same as '-j any'\n"
" -c count Set event sample period.\n"
- " -e event Select the event to sample (Use `simpleperf list`)\n"
- " to find all possible event names.\n"
+ " -e event[:modifier]\n"
+ " Select the event to sample. Use `simpleperf list` to find\n"
+ " all possible event names. Modifiers can be added to define\n"
+ " how the event should be monitored. Possible modifiers are:\n"
+ " u - monitor user space events only\n"
+ " k - monitor kernel space events only\n"
" -f freq Set event sample frequency.\n"
" -F freq Same as '-f freq'.\n"
" -g Enables call-graph recording.\n"
@@ -88,7 +92,6 @@ class RecordCommand : public Command {
system_wide_collection_(false),
branch_sampling_(0),
callchain_sampling_(false),
- measured_event_type_(nullptr),
perf_mmap_pages_(256),
record_filename_("perf.data") {
signaled = false;
@@ -117,8 +120,8 @@ class RecordCommand : public Command {
bool system_wide_collection_;
std::vector<pid_t> monitored_threads_;
uint64_t branch_sampling_;
+ std::unique_ptr<EventTypeAndModifier> measured_event_type_modifier_;
bool callchain_sampling_;
- const EventType* measured_event_type_;
EventSelectionSet event_selection_set_;
// mmap pages used by each perf event file, should be power of 2.
@@ -136,7 +139,7 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
if (!ParseOptions(args, &workload_args)) {
return false;
}
- if (measured_event_type_ == nullptr) {
+ if (measured_event_type_modifier_ == nullptr) {
if (!SetMeasuredEventType(default_measured_event_type)) {
return false;
}
@@ -182,8 +185,9 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
// 4. Open record file writer, and dump kernel/modules/threads mmap information.
record_file_writer_ = RecordFileWriter::CreateInstance(
- record_filename_, event_selection_set_.FindEventAttrByType(*measured_event_type_),
- event_selection_set_.FindEventFdsByType(*measured_event_type_));
+ record_filename_,
+ event_selection_set_.FindEventAttrByType(measured_event_type_modifier_->event_type),
+ event_selection_set_.FindEventFdsByType(measured_event_type_modifier_->event_type));
if (record_file_writer_ == nullptr) {
return false;
}
@@ -320,16 +324,16 @@ bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
}
bool RecordCommand::SetMeasuredEventType(const std::string& event_type_name) {
- const EventType* event_type = EventTypeFactory::FindEventTypeByName(event_type_name);
- if (event_type == nullptr) {
+ std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType(event_type_name);
+ if (event_type_modifier == nullptr) {
return false;
}
- measured_event_type_ = event_type;
+ measured_event_type_modifier_ = std::move(event_type_modifier);
return true;
}
bool RecordCommand::SetEventSelection() {
- event_selection_set_.AddEventType(*measured_event_type_);
+ event_selection_set_.AddEventType(*measured_event_type_modifier_);
if (use_sample_freq_) {
event_selection_set_.SetSampleFreq(sample_freq_);
} else {
@@ -355,7 +359,8 @@ bool RecordCommand::DumpKernelAndModuleMmaps() {
if (!GetKernelAndModuleMmaps(&kernel_mmap, &module_mmaps)) {
return false;
}
- const perf_event_attr& attr = event_selection_set_.FindEventAttrByType(*measured_event_type_);
+ const perf_event_attr& attr =
+ event_selection_set_.FindEventAttrByType(measured_event_type_modifier_->event_type);
MmapRecord mmap_record = CreateMmapRecord(attr, true, UINT_MAX, 0, kernel_mmap.start_addr,
kernel_mmap.len, kernel_mmap.pgoff, kernel_mmap.name);
if (!record_file_writer_->WriteData(mmap_record.BinaryFormat())) {
@@ -380,7 +385,8 @@ bool RecordCommand::DumpThreadCommAndMmaps() {
if (!GetThreadComms(&thread_comms)) {
return false;
}
- const perf_event_attr& attr = event_selection_set_.FindEventAttrByType(*measured_event_type_);
+ const perf_event_attr& attr =
+ event_selection_set_.FindEventAttrByType(measured_event_type_modifier_->event_type);
for (auto& thread : thread_comms) {
CommRecord record = CreateCommRecord(attr, thread.tgid, thread.tid, thread.comm);
if (!record_file_writer_->WriteData(record.BinaryFormat())) {
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index dcc0ad12..a4e2be6f 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -103,6 +103,10 @@ TEST(record_cmd, branch_sampling) {
}
}
+TEST(record_cmd, event_modifier) {
+ ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles:u", "sleep", "1"}));
+}
+
TEST(record_cmd, callchain_sampling) {
ASSERT_TRUE(RecordCmd()->Run({"-g", "sleep", "1"}));
}
diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp
index 73452abe..cdb71695 100644
--- a/simpleperf/cmd_report.cpp
+++ b/simpleperf/cmd_report.cpp
@@ -312,8 +312,7 @@ void ReportCommand::PrintReport() {
}
void ReportCommand::PrintReportContext() {
- const EventType* event_type =
- EventTypeFactory::FindEventTypeByConfig(event_attr_.type, event_attr_.config);
+ const EventType* event_type = FindEventTypeByConfig(event_attr_.type, event_attr_.config);
std::string event_type_name;
if (event_type != nullptr) {
event_type_name = event_type->name;
diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp
index 8feb1a65..cba28734 100644
--- a/simpleperf/cmd_stat.cpp
+++ b/simpleperf/cmd_stat.cpp
@@ -51,8 +51,12 @@ class StatCommand : public Command {
"Usage: simpleperf stat [options] [command [command-args]]\n"
" Gather performance counter information of running [command].\n"
" -a Collect system-wide information.\n"
- " -e event1,event2,... Select the event list to count. Use `simpleperf list`\n"
- " to find all possible event names.\n"
+ " -e event1[:modifier1],event2[:modifier2],...\n"
+ " Select the event list to count. Use `simpleperf list` to find\n"
+ " all possible event names. Modifiers can be added to define\n"
+ " how the event should be monitored. Possible modifiers are:\n"
+ " u - monitor user space events only\n"
+ " k - monitor kernel space events only\n"
" -p pid1,pid2,...\n"
" Stat events on existing processes. Mutually exclusive with -a.\n"
" -t tid1,tid2,...\n"
@@ -74,6 +78,7 @@ class StatCommand : public Command {
bool ShowCounters(const std::map<const EventType*, std::vector<PerfCounter>>& counters_map,
std::chrono::steady_clock::duration counting_duration);
+ std::vector<std::pair<std::string, EventType>> measured_event_types_;
EventSelectionSet event_selection_set_;
bool verbose_mode_;
bool system_wide_collection_;
@@ -207,12 +212,13 @@ bool StatCommand::ParseOptions(const std::vector<std::string>& args,
bool StatCommand::AddMeasuredEventType(const std::string& event_type_name,
bool report_unsupported_type) {
- const EventType* event_type =
- EventTypeFactory::FindEventTypeByName(event_type_name, report_unsupported_type);
- if (event_type == nullptr) {
+ std::unique_ptr<EventTypeAndModifier> event_type_modifier =
+ ParseEventType(event_type_name, report_unsupported_type);
+ if (event_type_modifier == nullptr) {
return false;
}
- event_selection_set_.AddEventType(*event_type);
+ measured_event_types_.push_back(std::make_pair(event_type_name, event_type_modifier->event_type));
+ event_selection_set_.AddEventType(*event_type_modifier);
return true;
}
@@ -263,8 +269,14 @@ bool StatCommand::ShowCounters(
sum_counter.time_enabled / sum_counter.time_running);
}
}
+ std::string event_type_name;
+ for (auto& pair : measured_event_types_) {
+ if (pair.second.name == event_type->name) {
+ event_type_name = pair.first;
+ }
+ }
printf("%'30" PRId64 "%s %s\n", scaled_count, scaled ? "(scaled)" : " ",
- event_type->name.c_str());
+ event_type_name.c_str());
}
printf("\nTotal test time: %lf seconds.\n",
std::chrono::duration_cast<std::chrono::duration<double>>(counting_duration).count());
diff --git a/simpleperf/cmd_stat_test.cpp b/simpleperf/cmd_stat_test.cpp
index 36d79da0..c6c4ef74 100644
--- a/simpleperf/cmd_stat_test.cpp
+++ b/simpleperf/cmd_stat_test.cpp
@@ -21,54 +21,51 @@
#include "command.h"
#include "test_util.h"
-class StatCommandTest : public ::testing::Test {
- protected:
- virtual void SetUp() {
- stat_cmd = CreateCommandInstance("stat");
- ASSERT_TRUE(stat_cmd != nullptr);
- }
+static std::unique_ptr<Command> StatCmd() {
+ return CreateCommandInstance("stat");
+}
- protected:
- std::unique_ptr<Command> stat_cmd;
-};
+TEST(stat_cmd, no_options) {
+ ASSERT_TRUE(StatCmd()->Run({"sleep", "1"}));
+}
-TEST_F(StatCommandTest, no_options) {
- ASSERT_TRUE(stat_cmd->Run({"sleep", "1"}));
+TEST(stat_cmd, event_option) {
+ ASSERT_TRUE(StatCmd()->Run({"-e", "cpu-clock,task-clock", "sleep", "1"}));
}
-TEST_F(StatCommandTest, event_option) {
- ASSERT_TRUE(stat_cmd->Run({"-e", "cpu-clock,task-clock", "sleep", "1"}));
+TEST(stat_cmd, system_wide_option) {
+ ASSERT_TRUE(StatCmd()->Run({"-a", "sleep", "1"}));
}
-TEST_F(StatCommandTest, system_wide_option) {
- ASSERT_TRUE(stat_cmd->Run({"-a", "sleep", "1"}));
+TEST(stat_cmd, verbose_option) {
+ ASSERT_TRUE(StatCmd()->Run({"--verbose", "sleep", "1"}));
}
-TEST_F(StatCommandTest, verbose_option) {
- ASSERT_TRUE(stat_cmd->Run({"--verbose", "sleep", "1"}));
+TEST(stat_cmd, tracepoint_event) {
+ ASSERT_TRUE(StatCmd()->Run({"-a", "-e", "sched:sched_switch", "sleep", "1"}));
}
-TEST_F(StatCommandTest, tracepoint_event) {
- ASSERT_TRUE(stat_cmd->Run({"-a", "-e", "sched:sched_switch", "sleep", "1"}));
+TEST(stat_cmd, event_modifier) {
+ ASSERT_TRUE(StatCmd()->Run({"-e", "cpu-cycles:u,sched:sched_switch:k", "sleep", "1"}));
}
-TEST_F(StatCommandTest, existing_processes) {
+TEST(stat_cmd, existing_processes) {
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(2, &workloads);
std::string pid_list =
android::base::StringPrintf("%d,%d", workloads[0]->GetPid(), workloads[1]->GetPid());
- ASSERT_TRUE(stat_cmd->Run({"-p", pid_list}));
+ ASSERT_TRUE(StatCmd()->Run({"-p", pid_list}));
}
-TEST_F(StatCommandTest, existing_threads) {
+TEST(stat_cmd, existing_threads) {
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(2, &workloads);
// Process id can be used as thread id in linux.
std::string tid_list =
android::base::StringPrintf("%d,%d", workloads[0]->GetPid(), workloads[1]->GetPid());
- ASSERT_TRUE(stat_cmd->Run({"-t", tid_list}));
+ ASSERT_TRUE(StatCmd()->Run({"-t", tid_list}));
}
-TEST_F(StatCommandTest, no_monitored_threads) {
- ASSERT_FALSE(stat_cmd->Run({""}));
+TEST(stat_cmd, no_monitored_threads) {
+ ASSERT_FALSE(StatCmd()->Run({""}));
}
diff --git a/simpleperf/cpu_offline_test.cpp b/simpleperf/cpu_offline_test.cpp
index 608bdf21..723518aa 100644
--- a/simpleperf/cpu_offline_test.cpp
+++ b/simpleperf/cpu_offline_test.cpp
@@ -25,11 +25,11 @@
#include "event_type.h"
static std::unique_ptr<EventFd> OpenHardwareEventOnCpu0() {
- const EventType* event_type = EventTypeFactory::FindEventTypeByName("cpu-cycles");
- if (event_type == nullptr) {
+ std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType("cpu-cycles");
+ if (event_type_modifier == nullptr) {
return nullptr;
}
- perf_event_attr attr = CreateDefaultPerfEventAttr(*event_type);
+ perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type);
return EventFd::OpenEventFile(attr, getpid(), 0);
}
diff --git a/simpleperf/event_attr.cpp b/simpleperf/event_attr.cpp
index 5e02215e..c9947c9d 100644
--- a/simpleperf/event_attr.cpp
+++ b/simpleperf/event_attr.cpp
@@ -95,7 +95,7 @@ perf_event_attr CreateDefaultPerfEventAttr(const EventType& event_type) {
void DumpPerfEventAttr(const perf_event_attr& attr, size_t indent) {
std::string event_name = "unknown";
- const EventType* event_type = EventTypeFactory::FindEventTypeByConfig(attr.type, attr.config);
+ const EventType* event_type = FindEventTypeByConfig(attr.type, attr.config);
if (event_type != nullptr) {
event_name = event_type->name;
}
@@ -116,21 +116,21 @@ void DumpPerfEventAttr(const perf_event_attr& attr, size_t indent) {
PrintIndented(indent + 1, "read_format (0x%llx) %s\n", attr.read_format,
ReadFormatToString(attr.read_format).c_str());
- PrintIndented(indent + 1, "disabled %llu, inherit %llu, pinned %llu, exclusive %llu\n",
+ PrintIndented(indent + 1, "disabled %u, inherit %u, pinned %u, exclusive %u\n",
attr.disabled, attr.inherit, attr.pinned, attr.exclusive);
- PrintIndented(indent + 1, "exclude_user %llu, exclude_kernel %llu, exclude_hv %llu\n",
+ PrintIndented(indent + 1, "exclude_user %u, exclude_kernel %u, exclude_hv %u\n",
attr.exclude_user, attr.exclude_kernel, attr.exclude_hv);
- PrintIndented(indent + 1, "exclude_idle %llu, mmap %llu, comm %llu, freq %llu\n",
+ PrintIndented(indent + 1, "exclude_idle %u, mmap %u, comm %u, freq %u\n",
attr.exclude_idle, attr.mmap, attr.comm, attr.freq);
- PrintIndented(indent + 1, "inherit_stat %llu, enable_on_exec %llu, task %llu\n",
+ PrintIndented(indent + 1, "inherit_stat %u, enable_on_exec %u, task %u\n",
attr.inherit_stat, attr.enable_on_exec, attr.task);
- PrintIndented(indent + 1, "watermark %llu, precise_ip %llu, mmap_data %llu\n", attr.watermark,
+ PrintIndented(indent + 1, "watermark %u, precise_ip %u, mmap_data %u\n", attr.watermark,
attr.precise_ip, attr.mmap_data);
- PrintIndented(indent + 1, "sample_id_all %llu, exclude_host %llu, exclude_guest %llu\n",
+ PrintIndented(indent + 1, "sample_id_all %u, exclude_host %u, exclude_guest %u\n",
attr.sample_id_all, attr.exclude_host, attr.exclude_guest);
}
diff --git a/simpleperf/event_fd.cpp b/simpleperf/event_fd.cpp
index 9b06e50b..547be299 100644
--- a/simpleperf/event_fd.cpp
+++ b/simpleperf/event_fd.cpp
@@ -42,8 +42,7 @@ std::unique_ptr<EventFd> EventFd::OpenEventFile(const perf_event_attr& attr, pid
bool report_error) {
perf_event_attr perf_attr = attr;
std::string event_name = "unknown event";
- const EventType* event_type =
- EventTypeFactory::FindEventTypeByConfig(perf_attr.type, perf_attr.config);
+ const EventType* event_type = FindEventTypeByConfig(perf_attr.type, perf_attr.config);
if (event_type != nullptr) {
event_name = event_type->name;
}
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index f03286bc..e89a19ff 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -23,21 +23,27 @@
#include "event_type.h"
bool IsBranchSamplingSupported() {
- const EventType* event_type = EventTypeFactory::FindEventTypeByName("cpu-cycles", false);
- if (event_type == nullptr) {
+ std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType("cpu-cycles", false);
+ if (event_type_modifier == nullptr) {
return false;
}
- perf_event_attr attr = CreateDefaultPerfEventAttr(*event_type);
+ perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type);
attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY;
auto event_fd = EventFd::OpenEventFile(attr, getpid(), -1, false);
return event_fd != nullptr;
}
-void EventSelectionSet::AddEventType(const EventType& event_type) {
+void EventSelectionSet::AddEventType(const EventTypeAndModifier& event_type_modifier) {
EventSelection selection;
- selection.event_type = &event_type;
- selection.event_attr = CreateDefaultPerfEventAttr(event_type);
+ selection.event_type = event_type_modifier.event_type;
+ selection.event_attr = CreateDefaultPerfEventAttr(event_type_modifier.event_type);
+ selection.event_attr.exclude_user = event_type_modifier.exclude_user;
+ selection.event_attr.exclude_kernel = event_type_modifier.exclude_kernel;
+ selection.event_attr.exclude_hv = event_type_modifier.exclude_hv;
+ selection.event_attr.exclude_host = event_type_modifier.exclude_host;
+ selection.event_attr.exclude_guest = event_type_modifier.exclude_guest;
+ selection.event_attr.precise_ip = event_type_modifier.precise_ip;
selections_.push_back(std::move(selection));
}
@@ -122,7 +128,7 @@ bool EventSelectionSet::OpenEventFilesForAllCpus() {
// As the online cpus can be enabled or disabled at runtime, we may not open event file for
// all cpus successfully. But we should open at least one cpu successfully.
if (selection.event_fds.empty()) {
- PLOG(ERROR) << "failed to open perf event file for event_type " << selection.event_type->name
+ PLOG(ERROR) << "failed to open perf event file for event_type " << selection.event_type.name
<< " on all cpus";
return false;
}
@@ -165,7 +171,7 @@ bool EventSelectionSet::ReadCounters(
}
counters.push_back(counter);
}
- counters_map->insert(std::make_pair(selection.event_type, counters));
+ counters_map->insert(std::make_pair(&selection.event_type, counters));
}
return true;
}
@@ -241,7 +247,7 @@ std::string EventSelectionSet::FindEventFileNameById(uint64_t id) {
EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType(
const EventType& event_type) {
for (auto& selection : selections_) {
- if (selection.event_type->name == event_type.name) {
+ if (selection.event_type.name == event_type.name) {
return &selection;
}
}
diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h
index 2e5b50cc..6f7f8f4f 100644
--- a/simpleperf/event_selection_set.h
+++ b/simpleperf/event_selection_set.h
@@ -25,10 +25,9 @@
#include <base/macros.h>
#include "event_fd.h"
+#include "event_type.h"
#include "perf_event.h"
-struct EventType;
-
// EventSelectionSet helps to monitor events.
// Firstly, the user creates an EventSelectionSet, and adds the specific event types to monitor.
// Secondly, the user defines how to monitor the events (by setting enable_on_exec flag,
@@ -47,7 +46,7 @@ class EventSelectionSet {
return selections_.empty();
}
- void AddEventType(const EventType& event_type);
+ void AddEventType(const EventTypeAndModifier& event_type_modifier);
void SetEnableOnExec(bool enable);
bool GetEnableOnExec();
@@ -71,7 +70,7 @@ class EventSelectionSet {
private:
struct EventSelection {
- const EventType* event_type;
+ EventType event_type;
perf_event_attr event_attr;
std::vector<std::unique_ptr<EventFd>> event_fds;
};
diff --git a/simpleperf/event_type.cpp b/simpleperf/event_type.cpp
index 2b2e5b49..56a17b8c 100644
--- a/simpleperf/event_type.cpp
+++ b/simpleperf/event_type.cpp
@@ -75,7 +75,7 @@ static const std::vector<EventType> GetTracepointEventTypes() {
return result;
}
-const std::vector<EventType>& EventTypeFactory::GetAllEventTypes() {
+const std::vector<EventType>& GetAllEventTypes() {
static std::vector<EventType> event_type_array;
if (event_type_array.empty()) {
event_type_array.insert(event_type_array.end(), static_event_type_array.begin(),
@@ -87,8 +87,16 @@ const std::vector<EventType>& EventTypeFactory::GetAllEventTypes() {
return event_type_array;
}
-const EventType* EventTypeFactory::FindEventTypeByName(const std::string& name,
- bool report_unsupported_type) {
+const EventType* FindEventTypeByConfig(uint32_t type, uint64_t config) {
+ for (auto& event_type : GetAllEventTypes()) {
+ if (event_type.type == type && event_type.config == config) {
+ return &event_type;
+ }
+ }
+ return nullptr;
+}
+
+static const EventType* FindEventTypeByName(const std::string& name, bool report_unsupported_type) {
const EventType* result = nullptr;
for (auto& event_type : GetAllEventTypes()) {
if (event_type.name == name) {
@@ -109,11 +117,75 @@ const EventType* EventTypeFactory::FindEventTypeByName(const std::string& name,
return result;
}
-const EventType* EventTypeFactory::FindEventTypeByConfig(uint32_t type, uint64_t config) {
- for (auto& event_type : GetAllEventTypes()) {
- if (event_type.type == type && event_type.config == config) {
- return &event_type;
+std::unique_ptr<EventTypeAndModifier> ParseEventType(const std::string& event_type_str,
+ bool report_unsupported_type) {
+ static std::string modifier_characters = "ukhGHp";
+ std::unique_ptr<EventTypeAndModifier> event_type_modifier(new EventTypeAndModifier);
+ std::string name = event_type_str;
+ std::string modifier;
+ size_t comm_pos = event_type_str.rfind(':');
+ if (comm_pos != std::string::npos) {
+ bool match_modifier = true;
+ for (size_t i = comm_pos + 1; i < event_type_str.size(); ++i) {
+ char c = event_type_str[i];
+ if (c != ' ' && modifier_characters.find(c) == std::string::npos) {
+ match_modifier = false;
+ break;
+ }
+ }
+ if (match_modifier) {
+ name = event_type_str.substr(0, comm_pos);
+ modifier = event_type_str.substr(comm_pos + 1);
}
}
- return nullptr;
+ const EventType* event_type = FindEventTypeByName(name, report_unsupported_type);
+ if (event_type == nullptr) {
+ // Try if the modifier belongs to the event type name, like some tracepoint events.
+ if (!modifier.empty()) {
+ name = event_type_str;
+ modifier.clear();
+ event_type = FindEventTypeByName(name, report_unsupported_type);
+ }
+ if (event_type == nullptr) {
+ return nullptr;
+ }
+ }
+ event_type_modifier->event_type = *event_type;
+ if (modifier.find_first_of("ukh") != std::string::npos) {
+ event_type_modifier->exclude_user = true;
+ event_type_modifier->exclude_kernel = true;
+ event_type_modifier->exclude_hv = true;
+ }
+ if (modifier.find_first_of("GH") != std::string::npos) {
+ event_type_modifier->exclude_guest = true;
+ event_type_modifier->exclude_host = true;
+ }
+
+ for (auto& c : modifier) {
+ switch (c) {
+ case 'u':
+ event_type_modifier->exclude_user = false;
+ break;
+ case 'k':
+ event_type_modifier->exclude_kernel = false;
+ break;
+ case 'h':
+ event_type_modifier->exclude_hv = false;
+ break;
+ case 'G':
+ event_type_modifier->exclude_guest = false;
+ break;
+ case 'H':
+ event_type_modifier->exclude_host = false;
+ break;
+ case 'p':
+ event_type_modifier->precise_ip++;
+ break;
+ case ' ':
+ break;
+ default:
+ LOG(ERROR) << "Unknown event type modifier '" << c << "'";
+ }
+ }
+ return event_type_modifier;
}
diff --git a/simpleperf/event_type.h b/simpleperf/event_type.h
index 341d2c4f..9c365faf 100644
--- a/simpleperf/event_type.h
+++ b/simpleperf/event_type.h
@@ -18,6 +18,7 @@
#define SIMPLE_PERF_EVENT_H_
#include <stdint.h>
+#include <memory>
#include <string>
#include <vector>
@@ -41,12 +42,29 @@ struct EventType {
uint64_t config;
};
-class EventTypeFactory {
- public:
- static const std::vector<EventType>& GetAllEventTypes();
- static const EventType* FindEventTypeByName(const std::string& name,
- bool report_unsupported_type = true);
- static const EventType* FindEventTypeByConfig(uint32_t type, uint64_t config);
+const std::vector<EventType>& GetAllEventTypes();
+const EventType* FindEventTypeByConfig(uint32_t type, uint64_t config);
+
+struct EventTypeAndModifier {
+ EventType event_type;
+ bool exclude_user;
+ bool exclude_kernel;
+ bool exclude_hv;
+ bool exclude_host;
+ bool exclude_guest;
+ int precise_ip : 2;
+
+ EventTypeAndModifier()
+ : exclude_user(false),
+ exclude_kernel(false),
+ exclude_hv(false),
+ exclude_host(false),
+ exclude_guest(false),
+ precise_ip(0) {
+ }
};
+std::unique_ptr<EventTypeAndModifier> ParseEventType(const std::string& event_type_str,
+ bool report_unsupported_type = true);
+
#endif // SIMPLE_PERF_EVENT_H_
diff --git a/simpleperf/record_file_test.cpp b/simpleperf/record_file_test.cpp
index 2d595110..c4bb255d 100644
--- a/simpleperf/record_file_test.cpp
+++ b/simpleperf/record_file_test.cpp
@@ -32,9 +32,9 @@ class RecordFileTest : public ::testing::Test {
protected:
virtual void SetUp() {
filename = "temporary.record_file";
- const EventType* event_type = EventTypeFactory::FindEventTypeByName("cpu-cycles");
- ASSERT_TRUE(event_type != nullptr);
- event_attr = CreateDefaultPerfEventAttr(*event_type);
+ std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType("cpu-cycles");
+ ASSERT_TRUE(event_type_modifier != nullptr);
+ event_attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type);
event_attr.sample_id_all = 1;
event_attr.sample_type |= PERF_SAMPLE_TIME;
std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(event_attr, getpid(), -1);
diff --git a/simpleperf/record_test.cpp b/simpleperf/record_test.cpp
index d9e9a4bd..a15972b6 100644
--- a/simpleperf/record_test.cpp
+++ b/simpleperf/record_test.cpp
@@ -24,9 +24,9 @@
class RecordTest : public ::testing::Test {
protected:
virtual void SetUp() {
- const EventType* event_type = EventTypeFactory::FindEventTypeByName("cpu-cycles");
- ASSERT_TRUE(event_type != nullptr);
- event_attr = CreateDefaultPerfEventAttr(*event_type);
+ std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType("cpu-cycles");
+ ASSERT_TRUE(event_type_modifier != nullptr);
+ event_attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type);
}
template <class RecordType>