diff options
-rw-r--r-- | simpleperf/cmd_list.cpp | 2 | ||||
-rw-r--r-- | simpleperf/cmd_record.cpp | 32 | ||||
-rw-r--r-- | simpleperf/cmd_record_test.cpp | 4 | ||||
-rw-r--r-- | simpleperf/cmd_report.cpp | 3 | ||||
-rw-r--r-- | simpleperf/cmd_stat.cpp | 26 | ||||
-rw-r--r-- | simpleperf/cmd_stat_test.cpp | 47 | ||||
-rw-r--r-- | simpleperf/cpu_offline_test.cpp | 6 | ||||
-rw-r--r-- | simpleperf/event_attr.cpp | 14 | ||||
-rw-r--r-- | simpleperf/event_fd.cpp | 3 | ||||
-rw-r--r-- | simpleperf/event_selection_set.cpp | 24 | ||||
-rw-r--r-- | simpleperf/event_selection_set.h | 7 | ||||
-rw-r--r-- | simpleperf/event_type.cpp | 88 | ||||
-rw-r--r-- | simpleperf/event_type.h | 30 | ||||
-rw-r--r-- | simpleperf/record_file_test.cpp | 6 | ||||
-rw-r--r-- | simpleperf/record_test.cpp | 6 |
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> |