summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--simpleperf/cmd_list.cpp46
-rw-r--r--simpleperf/cmd_list_test.cpp22
-rw-r--r--simpleperf/cmd_record_test.cpp4
-rw-r--r--simpleperf/cmd_stat.cpp7
-rw-r--r--simpleperf/cmd_stat_test.cpp4
-rw-r--r--simpleperf/environment.h1
-rw-r--r--simpleperf/event_attr.cpp17
-rw-r--r--simpleperf/event_attr.h3
-rw-r--r--simpleperf/event_fd.cpp1
-rw-r--r--simpleperf/event_selection_set.cpp2
-rw-r--r--simpleperf/event_type.cpp48
-rw-r--r--simpleperf/event_type.h11
-rw-r--r--simpleperf/record.cpp15
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);