diff options
-rw-r--r-- | simpleperf/cmd_list.cpp | 46 | ||||
-rw-r--r-- | simpleperf/cmd_list_test.cpp | 22 | ||||
-rw-r--r-- | simpleperf/cmd_record_test.cpp | 4 | ||||
-rw-r--r-- | simpleperf/cmd_stat.cpp | 7 | ||||
-rw-r--r-- | simpleperf/cmd_stat_test.cpp | 4 | ||||
-rw-r--r-- | simpleperf/environment.h | 1 | ||||
-rw-r--r-- | simpleperf/event_attr.cpp | 17 | ||||
-rw-r--r-- | simpleperf/event_attr.h | 3 | ||||
-rw-r--r-- | simpleperf/event_fd.cpp | 1 | ||||
-rw-r--r-- | simpleperf/event_selection_set.cpp | 2 | ||||
-rw-r--r-- | simpleperf/event_type.cpp | 48 | ||||
-rw-r--r-- | simpleperf/event_type.h | 11 | ||||
-rw-r--r-- | simpleperf/record.cpp | 15 |
13 files changed, 137 insertions, 44 deletions
diff --git a/simpleperf/cmd_list.cpp b/simpleperf/cmd_list.cpp index 923a884f..18c3972b 100644 --- a/simpleperf/cmd_list.cpp +++ b/simpleperf/cmd_list.cpp @@ -15,6 +15,7 @@ */ #include <stdio.h> +#include <map> #include <string> #include <vector> @@ -24,12 +25,12 @@ #include "event_type.h" #include "perf_event.h" -static void PrintEventTypesOfType(uint32_t type, const char* type_name, - const std::vector<const EventType>& event_types) { - printf("List of %s:\n", type_name); +static void PrintEventTypesOfType(uint32_t type, const std::string& type_name, + const std::vector<EventType>& event_types) { + printf("List of %s:\n", type_name.c_str()); for (auto& event_type : event_types) { if (event_type.type == type && event_type.IsSupportedByKernel()) { - printf(" %s\n", event_type.name); + printf(" %s\n", event_type.name.c_str()); } } printf("\n"); @@ -38,8 +39,8 @@ static void PrintEventTypesOfType(uint32_t type, const char* type_name, class ListCommand : public Command { public: ListCommand() - : Command("list", "list all available perf events", - "Usage: simpleperf list\n" + : Command("list", "list available event types", + "Usage: simpleperf list [hw|sw|cache|tracepoint]\n" " List all available perf events on this machine.\n") { } @@ -47,16 +48,35 @@ class ListCommand : public Command { }; bool ListCommand::Run(const std::vector<std::string>& args) { - if (args.size() != 1) { - LOG(ERROR) << "malformed command line: list subcommand needs no argument"; - LOG(ERROR) << "try using \"help list\""; - return false; + static std::map<std::string, std::pair<int, std::string>> type_map = { + {"hw", {PERF_TYPE_HARDWARE, "hardware events"}}, + {"sw", {PERF_TYPE_SOFTWARE, "software events"}}, + {"cache", {PERF_TYPE_HW_CACHE, "hw-cache events"}}, + {"tracepoint", {PERF_TYPE_TRACEPOINT, "tracepoint events"}}, + }; + + std::vector<std::string> names; + if (args.size() == 1) { + for (auto& item : type_map) { + names.push_back(item.first); + } + } else { + for (size_t i = 1; i < args.size(); ++i) { + if (type_map.find(args[i]) != type_map.end()) { + names.push_back(args[i]); + } else { + LOG(ERROR) << "unknown event type category: " << args[i] << ", try using \"help list\""; + return false; + } + } } + auto& event_types = EventTypeFactory::GetAllEventTypes(); - PrintEventTypesOfType(PERF_TYPE_HARDWARE, "hardware events", event_types); - PrintEventTypesOfType(PERF_TYPE_SOFTWARE, "software events", event_types); - PrintEventTypesOfType(PERF_TYPE_HW_CACHE, "hw-cache events", event_types); + for (auto& name : names) { + auto it = type_map.find(name); + PrintEventTypesOfType(it->second.first, it->second.second, event_types); + } return true; } diff --git a/simpleperf/cmd_list_test.cpp b/simpleperf/cmd_list_test.cpp index 4b873a14..ddc82ca7 100644 --- a/simpleperf/cmd_list_test.cpp +++ b/simpleperf/cmd_list_test.cpp @@ -18,8 +18,24 @@ #include "command.h" -TEST(cmd_list, smoke) { - Command* list_cmd = Command::FindCommandByName("list"); - ASSERT_TRUE(list_cmd != nullptr); +class ListCommandTest : public ::testing::Test { + protected: + virtual void SetUp() { + list_cmd = Command::FindCommandByName("list"); + ASSERT_TRUE(list_cmd != nullptr); + } + + Command* list_cmd; +}; + +TEST_F(ListCommandTest, no_options) { ASSERT_TRUE(list_cmd->Run({"list"})); } + +TEST_F(ListCommandTest, one_option) { + ASSERT_TRUE(list_cmd->Run({"list", "sw"})); +} + +TEST_F(ListCommandTest, multiple_options) { + ASSERT_TRUE(list_cmd->Run({"list", "hw", "tracepoint"})); +} diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp index f0a8878b..9e332bb3 100644 --- a/simpleperf/cmd_record_test.cpp +++ b/simpleperf/cmd_record_test.cpp @@ -86,3 +86,7 @@ TEST_F(RecordCommandTest, dump_build_id_feature) { ASSERT_TRUE(file_header->features[FEAT_BUILD_ID / 8] & (1 << (FEAT_BUILD_ID % 8))); ASSERT_GT(reader->FeatureSectionDescriptors().size(), 0u); } + +TEST_F(RecordCommandTest, tracepoint_event) { + ASSERT_TRUE(record_cmd->Run({"record", "-a", "-e", "sched:sched_switch", "sleep", "1"})); +} diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp index c8e59d97..16af81e6 100644 --- a/simpleperf/cmd_stat.cpp +++ b/simpleperf/cmd_stat.cpp @@ -32,8 +32,9 @@ #include "workload.h" static std::vector<std::string> default_measured_event_types{ - "cpu-cycles", "stalled-cycles-frontend", "stalled-cycles-backend", "instructions", - "branch-instructions", "branch-misses", "task-clock", "context-switches", "page-faults", + "cpu-cycles", "stalled-cycles-frontend", "stalled-cycles-backend", + "instructions", "branch-instructions", "branch-misses", + "task-clock", "context-switches", "page-faults", }; class StatCommandImpl { @@ -210,7 +211,7 @@ bool StatCommandImpl::ShowCounters( } } printf("%'30" PRId64 "%s %s\n", scaled_count, scaled ? "(scaled)" : " ", - event_type->name); + 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 6a7a1cdb..0ed49bcb 100644 --- a/simpleperf/cmd_stat_test.cpp +++ b/simpleperf/cmd_stat_test.cpp @@ -44,3 +44,7 @@ TEST_F(StatCommandTest, system_wide_option) { TEST_F(StatCommandTest, verbose_option) { ASSERT_TRUE(stat_cmd->Run({"stat", "--verbose", "sleep", "1"})); } + +TEST_F(StatCommandTest, tracepoint_event) { + ASSERT_TRUE(stat_cmd->Run({"stat", "-a", "-e", "sched:sched_switch", "sleep", "1"})); +} diff --git a/simpleperf/environment.h b/simpleperf/environment.h index f81005ce..6d81e981 100644 --- a/simpleperf/environment.h +++ b/simpleperf/environment.h @@ -20,6 +20,7 @@ #include <functional> #include <string> #include <vector> + #include "build_id.h" std::vector<int> GetOnlineCpus(); diff --git a/simpleperf/event_attr.cpp b/simpleperf/event_attr.cpp index 2b059312..79ed4b84 100644 --- a/simpleperf/event_attr.cpp +++ b/simpleperf/event_attr.cpp @@ -46,17 +46,17 @@ static std::string BitsToString(const std::string& name, uint64_t bits, static std::string SampleTypeToString(uint64_t sample_type) { static std::vector<std::pair<int, std::string>> sample_type_names = { - {PERF_SAMPLE_IP, "ip"}, - {PERF_SAMPLE_TID, "tid"}, - {PERF_SAMPLE_TIME, "time"}, {PERF_SAMPLE_ADDR, "addr"}, - {PERF_SAMPLE_READ, "read"}, {PERF_SAMPLE_CALLCHAIN, "callchain"}, - {PERF_SAMPLE_ID, "id"}, {PERF_SAMPLE_CPU, "cpu"}, + {PERF_SAMPLE_ID, "id"}, + {PERF_SAMPLE_IP, "ip"}, {PERF_SAMPLE_PERIOD, "period"}, - {PERF_SAMPLE_STREAM_ID, "stream_id"}, {PERF_SAMPLE_RAW, "raw"}, + {PERF_SAMPLE_READ, "read"}, + {PERF_SAMPLE_STREAM_ID, "stream_id"}, + {PERF_SAMPLE_TID, "tid"}, + {PERF_SAMPLE_TIME, "time"}, }; return BitsToString("sample_type", sample_type, sample_type_names); } @@ -85,6 +85,11 @@ perf_event_attr CreateDefaultPerfEventAttr(const EventType& event_type) { attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID; attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_PERIOD; + + if (attr.type == PERF_TYPE_TRACEPOINT) { + attr.sample_freq = 0; + attr.sample_period = 1; + } return attr; } diff --git a/simpleperf/event_attr.h b/simpleperf/event_attr.h index 52f4aca7..79d3df45 100644 --- a/simpleperf/event_attr.h +++ b/simpleperf/event_attr.h @@ -17,8 +17,7 @@ #ifndef SIMPLE_PERF_EVENT_ATTR_H_ #define SIMPLE_PERF_EVENT_ATTR_H_ -#include <stdint.h> -#include <string> +#include <stddef.h> #include "perf_event.h" diff --git a/simpleperf/event_fd.cpp b/simpleperf/event_fd.cpp index 386685c2..f0a1ad56 100644 --- a/simpleperf/event_fd.cpp +++ b/simpleperf/event_fd.cpp @@ -22,6 +22,7 @@ #include <sys/mman.h> #include <sys/syscall.h> #include <sys/types.h> +#include <atomic> #include <memory> #include <base/file.h> diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp index 61f17050..858afa60 100644 --- a/simpleperf/event_selection_set.cpp +++ b/simpleperf/event_selection_set.cpp @@ -191,7 +191,7 @@ std::string EventSelectionSet::FindEventFileNameById(uint64_t id) { EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType( const EventType& event_type) { for (auto& selection : selections_) { - if (strcmp(selection.event_type->name, event_type.name) == 0) { + if (selection.event_type->name == event_type.name) { return &selection; } } diff --git a/simpleperf/event_type.cpp b/simpleperf/event_type.cpp index ee0e161f..a3b8fd2e 100644 --- a/simpleperf/event_type.cpp +++ b/simpleperf/event_type.cpp @@ -17,19 +17,22 @@ #include "event_type.h" #include <unistd.h> +#include <algorithm> #include <string> #include <vector> +#include <base/file.h> #include <base/logging.h> #include "event_attr.h" #include "event_fd.h" +#include "utils.h" #define EVENT_TYPE_TABLE_ENTRY(name, type, config) \ { name, type, config } \ , -static std::vector<const EventType> event_type_array = { +static const std::vector<EventType> static_event_type_array = { #include "event_type_table.h" }; @@ -42,14 +45,51 @@ bool EventType::IsSupportedByKernel() const { return IsEventTypeSupportedByKernel(*this); } -const std::vector<const EventType>& EventTypeFactory::GetAllEventTypes() { +static const std::vector<EventType> GetTracepointEventTypes() { + std::vector<EventType> result; + const std::string tracepoint_dirname = "/sys/kernel/debug/tracing/events"; + std::vector<std::string> system_dirs; + GetEntriesInDir(tracepoint_dirname, nullptr, &system_dirs); + for (auto& system_name : system_dirs) { + std::string system_path = tracepoint_dirname + "/" + system_name; + std::vector<std::string> event_dirs; + GetEntriesInDir(system_path, nullptr, &event_dirs); + for (auto& event_name : event_dirs) { + std::string id_path = system_path + "/" + event_name + "/id"; + std::string id_content; + if (!android::base::ReadFileToString(id_path, &id_content)) { + continue; + } + char* endptr; + uint64_t id = strtoull(id_content.c_str(), &endptr, 10); + if (endptr == id_content.c_str()) { + LOG(DEBUG) << "unexpected id '" << id_content << "' in " << id_path; + continue; + } + result.push_back(EventType(system_name + ":" + event_name, PERF_TYPE_TRACEPOINT, id)); + } + } + std::sort(result.begin(), result.end(), + [](const EventType& type1, const EventType& type2) { return type1.name < type2.name; }); + return result; +} + +const std::vector<EventType>& EventTypeFactory::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(), + static_event_type_array.end()); + const std::vector<EventType> tracepoint_array = GetTracepointEventTypes(); + event_type_array.insert(event_type_array.end(), tracepoint_array.begin(), + tracepoint_array.end()); + } return event_type_array; } const EventType* EventTypeFactory::FindEventTypeByName(const std::string& name, bool report_unsupported_type) { const EventType* result = nullptr; - for (auto& event_type : event_type_array) { + for (auto& event_type : GetAllEventTypes()) { if (event_type.name == name) { result = &event_type; break; @@ -69,7 +109,7 @@ const EventType* EventTypeFactory::FindEventTypeByName(const std::string& name, } const EventType* EventTypeFactory::FindEventTypeByConfig(uint32_t type, uint64_t config) { - for (auto& event_type : event_type_array) { + for (auto& event_type : GetAllEventTypes()) { if (event_type.type == type && event_type.config == config) { return &event_type; } diff --git a/simpleperf/event_type.h b/simpleperf/event_type.h index b486a294..341d2c4f 100644 --- a/simpleperf/event_type.h +++ b/simpleperf/event_type.h @@ -27,16 +27,23 @@ // the event type is supported by the kernel. struct EventType { + EventType(const std::string& name, uint32_t type, uint64_t config) + : name(name), type(type), config(config) { + } + + EventType() : type(0), config(0) { + } + bool IsSupportedByKernel() const; - const char* name; + std::string name; uint32_t type; uint64_t config; }; class EventTypeFactory { public: - static const std::vector<const EventType>& GetAllEventTypes(); + 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); diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp index 46910b92..71cb493a 100644 --- a/simpleperf/record.cpp +++ b/simpleperf/record.cpp @@ -27,16 +27,11 @@ static std::string RecordTypeToString(int record_type) { static std::unordered_map<int, std::string> record_type_names = { - {PERF_RECORD_MMAP, "mmap"}, - {PERF_RECORD_LOST, "lost"}, - {PERF_RECORD_COMM, "comm"}, - {PERF_RECORD_EXIT, "exit"}, - {PERF_RECORD_THROTTLE, "throttle"}, - {PERF_RECORD_UNTHROTTLE, "unthrottle"}, - {PERF_RECORD_FORK, "fork"}, - {PERF_RECORD_READ, "read"}, - {PERF_RECORD_SAMPLE, "sample"}, - {PERF_RECORD_BUILD_ID, "build_id"}, + {PERF_RECORD_MMAP, "mmap"}, {PERF_RECORD_LOST, "lost"}, + {PERF_RECORD_COMM, "comm"}, {PERF_RECORD_EXIT, "exit"}, + {PERF_RECORD_THROTTLE, "throttle"}, {PERF_RECORD_UNTHROTTLE, "unthrottle"}, + {PERF_RECORD_FORK, "fork"}, {PERF_RECORD_READ, "read"}, + {PERF_RECORD_SAMPLE, "sample"}, {PERF_RECORD_BUILD_ID, "build_id"}, }; auto it = record_type_names.find(record_type); |