summaryrefslogtreecommitdiff
path: root/simpleperf/event_type.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/event_type.cpp')
-rw-r--r--simpleperf/event_type.cpp566
1 files changed, 384 insertions, 182 deletions
diff --git a/simpleperf/event_type.cpp b/simpleperf/event_type.cpp
index 71c3d9f1..135e69da 100644
--- a/simpleperf/event_type.cpp
+++ b/simpleperf/event_type.cpp
@@ -28,17 +28,16 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include "environment.h"
#include "ETMRecorder.h"
+#include "environment.h"
#include "event_attr.h"
#include "utils.h"
-using namespace simpleperf;
+namespace simpleperf {
struct EventFormat {
EventFormat(const std::string& name, const std::string& attr, int shift)
- : name(name), attr(attr), shift(shift) {
- }
+ : name(name), attr(attr), shift(shift) {}
std::string name;
std::string attr;
@@ -46,188 +45,411 @@ struct EventFormat {
};
#define EVENT_TYPE_TABLE_ENTRY(name, type, config, description, limited_arch) \
- {name, type, config, description, limited_arch},
+ {name, type, config, description, limited_arch},
-static const std::vector<EventType> static_event_type_array = {
+static const std::set<EventType> builtin_event_types = {
#include "event_type_table.h"
};
-static std::string tracepoint_events;
-static std::set<EventType> g_event_types;
-static uint32_t g_etm_event_type;
+enum class EventFinderType {
+ BUILTIN,
+ TRACEPOINT_STRING,
+ TRACEPOINT_SYSTEM,
+ PMU,
+ ETM,
+ RAW,
+ SCOPED,
+};
-bool SetTracepointEventsFilePath(const std::string& filepath) {
- if (!android::base::ReadFileToString(filepath, &tracepoint_events)) {
- PLOG(ERROR) << "Failed to read " << filepath;
- return false;
+class EventTypeFinder {
+ public:
+ EventTypeFinder(EventFinderType type) : finder_type_(type) {}
+ virtual ~EventTypeFinder() {}
+
+ EventFinderType GetFinderType() const { return finder_type_; }
+
+ const std::set<EventType>& GetTypes() {
+ if (!loaded_) {
+ loaded_ = true;
+ LoadTypes();
+ }
+ return types_;
}
- return true;
-}
-std::string GetTracepointEvents() {
- std::string result;
- for (auto& event : GetAllEventTypes()) {
- if (event.type != PERF_TYPE_TRACEPOINT) {
- continue;
+ virtual const EventType* FindType(const std::string& name) {
+ const auto& types = GetTypes();
+ auto it = types.find(EventType(name, 0, 0, "", ""));
+ if (it != types.end()) {
+ return &*it;
}
- if (!result.empty()) {
- result.push_back('\n');
+ return nullptr;
+ }
+
+ protected:
+ virtual void LoadTypes() = 0;
+
+ const EventFinderType finder_type_;
+ std::set<EventType> types_;
+ bool loaded_ = false;
+};
+
+class BuiltinTypeFinder : public EventTypeFinder {
+ public:
+ BuiltinTypeFinder() : EventTypeFinder(EventFinderType::BUILTIN) {}
+
+ protected:
+ void LoadTypes() override { types_ = std::move(builtin_event_types); }
+};
+
+class TracepointStringFinder : public EventTypeFinder {
+ public:
+ TracepointStringFinder(std::string&& s)
+ : EventTypeFinder(EventFinderType::TRACEPOINT_STRING), s_(std::move(s)) {}
+
+ protected:
+ void LoadTypes() override {
+ for (const auto& line : android::base::Split(s_, "\n")) {
+ std::vector<std::string> items = android::base::Split(line, " ");
+ CHECK_EQ(items.size(), 2u);
+ std::string event_name = items[0];
+ uint64_t id;
+ CHECK(android::base::ParseUint(items[1].c_str(), &id));
+ types_.emplace(event_name, PERF_TYPE_TRACEPOINT, id, "", "");
}
- result += android::base::StringPrintf("%s %" PRIu64, event.name.c_str(), event.config);
}
- return result;
-}
-static std::vector<EventType> GetTracepointEventTypesFromString(const std::string& s) {
- std::vector<EventType> result;
- for (auto& line : android::base::Split(s, "\n")) {
- std::vector<std::string> items = android::base::Split(line, " ");
- CHECK_EQ(items.size(), 2u);
- std::string event_name = items[0];
+ private:
+ const std::string s_;
+};
+
+class TracepointSystemFinder : public EventTypeFinder {
+ public:
+ TracepointSystemFinder() : EventTypeFinder(EventFinderType::TRACEPOINT_SYSTEM) {}
+
+ const EventType* FindType(const std::string& name) override {
+ if (auto it = types_.find(EventType(name, 0, 0, "", "")); it != types_.end()) {
+ return &*it;
+ }
+ std::vector<std::string> strs = android::base::Split(name, ":");
+ if (strs.size() != 2) {
+ return nullptr;
+ }
+ const char* tracefs_dir = GetTraceFsDir();
+ if (tracefs_dir == nullptr) {
+ return nullptr;
+ }
+ std::string path = tracefs_dir + std::string("/events/") + strs[0] + "/" + strs[1] + "/id";
uint64_t id;
- CHECK(android::base::ParseUint(items[1].c_str(), &id));
- result.push_back(EventType(event_name, PERF_TYPE_TRACEPOINT, id, "", ""));
+ if (!ReadEventId(path, &id)) {
+ return nullptr;
+ }
+ auto res = types_.emplace(name, PERF_TYPE_TRACEPOINT, id, "", "");
+ return &*res.first;
}
- return result;
-}
-static std::vector<EventType> GetTracepointEventTypesFromTraceFs() {
- std::vector<EventType> result;
- const char* tracefs_dir = GetTraceFsDir();
- if (tracefs_dir == nullptr) {
+ void RemoveType(const std::string& name) { types_.erase(EventType(name, 0, 0, "", "")); }
+
+ std::string ToString() {
+ std::string result;
+ for (auto& type : GetTypes()) {
+ if (!result.empty()) {
+ result.push_back('\n');
+ }
+ result += android::base::StringPrintf("%s %" PRIu64, type.name.c_str(), type.config);
+ }
return result;
}
- const std::string tracepoint_dirname = tracefs_dir + std::string("/events");
- for (const auto& system_name : GetSubDirs(tracepoint_dirname)) {
- std::string system_path = tracepoint_dirname + "/" + system_name;
- for (const auto& event_name : GetSubDirs(system_path)) {
- std::string id_path = system_path + "/" + event_name + "/id";
- std::string id_content;
- if (!android::base::ReadFileToString(id_path, &id_content)) {
+
+ protected:
+ void LoadTypes() override {
+ const char* tracefs_dir = GetTraceFsDir();
+ if (tracefs_dir == nullptr) {
+ return;
+ }
+ const std::string tracepoint_dirname = tracefs_dir + std::string("/events");
+ for (const auto& system_name : GetSubDirs(tracepoint_dirname)) {
+ std::string system_path = tracepoint_dirname + "/" + system_name;
+ for (const auto& event_name : GetSubDirs(system_path)) {
+ std::string id_path = system_path + "/" + event_name + "/id";
+ uint64_t id;
+ if (ReadEventId(id_path, &id)) {
+ types_.emplace(system_name + ":" + event_name, PERF_TYPE_TRACEPOINT, id, "", "");
+ }
+ }
+ }
+ }
+
+ private:
+ bool ReadEventId(const std::string& id_path, uint64_t* id) {
+ std::string id_content;
+ if (!android::base::ReadFileToString(id_path, &id_content)) {
+ return false;
+ }
+ if (!android::base::ParseUint(android::base::Trim(id_content), id)) {
+ LOG(DEBUG) << "unexpected id '" << id_content << "' in " << id_path;
+ return false;
+ }
+ return true;
+ }
+};
+
+class PMUTypeFinder : public EventTypeFinder {
+ public:
+ PMUTypeFinder() : EventTypeFinder(EventFinderType::PMU) {}
+
+ const EventType* FindType(const std::string& name) override {
+ if (name.find('/') == std::string::npos) {
+ return nullptr;
+ }
+ return EventTypeFinder::FindType(name);
+ }
+
+ protected:
+ void LoadTypes() override {
+ const std::string evtsrc_dirname = "/sys/bus/event_source/devices/";
+ for (const auto& device_name : GetSubDirs(evtsrc_dirname)) {
+ std::string evtdev_path = evtsrc_dirname + device_name;
+ std::string type_path = evtdev_path + "/type";
+ std::string type_content;
+
+ if (!android::base::ReadFileToString(type_path, &type_content)) {
+ LOG(DEBUG) << "cannot read event type: " << device_name;
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;
+ uint64_t type_id = strtoull(type_content.c_str(), NULL, 10);
+
+ std::vector<EventFormat> formats = ParseEventFormats(evtdev_path);
+
+ std::string events_dirname = evtdev_path + "/events/";
+ for (const auto& event_name : GetEntriesInDir(events_dirname)) {
+ std::string event_path = events_dirname + event_name;
+ std::string event_content;
+ if (!android::base::ReadFileToString(event_path, &event_content)) {
+ LOG(DEBUG) << "cannot read event content in " << event_name;
+ continue;
+ }
+
+ uint64_t config = MakeEventConfig(event_content, formats);
+ if (config == ~0ULL) {
+ LOG(DEBUG) << "cannot handle config format in " << event_name;
+ continue;
+ }
+ types_.emplace(device_name + "/" + event_name + "/", type_id, config, "", "");
+ }
+ }
+ }
+
+ private:
+ std::vector<EventFormat> ParseEventFormats(const std::string& evtdev_path) {
+ std::vector<EventFormat> v;
+ std::string formats_dirname = evtdev_path + "/format/";
+ for (const auto& format_name : GetEntriesInDir(formats_dirname)) {
+ std::string format_path = formats_dirname + format_name;
+ std::string format_content;
+ if (!android::base::ReadFileToString(format_path, &format_content)) {
+ continue;
+ }
+
+ // format files look like below (currently only 'config' is supported) :
+ // # cat armv8_pmuv3/format/event
+ // config:0-15
+ int shift;
+ if (sscanf(format_content.c_str(), "config:%d", &shift) != 1) {
+ LOG(DEBUG) << "Invalid or unsupported event format: " << format_content;
continue;
}
- result.push_back(EventType(system_name + ":" + event_name, PERF_TYPE_TRACEPOINT, id, "", ""));
+
+ v.emplace_back(EventFormat(format_name, "config", shift));
}
+ return v;
}
- return result;
-}
-static std::vector<EventType> GetTracepointEventTypes() {
- std::vector<EventType> result;
- if (!tracepoint_events.empty()) {
- result = GetTracepointEventTypesFromString(tracepoint_events);
- } else {
- result = GetTracepointEventTypesFromTraceFs();
+ uint64_t MakeEventConfig(const std::string& event_str, std::vector<EventFormat>& formats) {
+ uint64_t config = 0;
+
+ // event files might have multiple terms, but usually have a term like:
+ // # cat armv8_pmuv3/events/cpu_cycles
+ // event=0x011
+ for (auto& s : android::base::Split(event_str, ",")) {
+ auto pos = s.find('=');
+ if (pos == std::string::npos) continue;
+
+ auto format = s.substr(0, pos);
+ long val;
+ if (!android::base::ParseInt(android::base::Trim(s.substr(pos + 1)), &val)) {
+ LOG(DEBUG) << "Invalid event format '" << s << "'";
+ continue;
+ }
+
+ for (auto& f : formats) {
+ if (f.name == format) {
+ if (f.attr != "config") {
+ LOG(DEBUG) << "cannot support other attribute: " << s;
+ return ~0ULL;
+ }
+
+ config |= val << f.shift;
+ break;
+ }
+ }
+ }
+ return config;
}
- std::sort(result.begin(), result.end(),
- [](const EventType& type1, const EventType& type2) { return type1.name < type2.name; });
- return result;
-}
+};
+
+class ETMTypeFinder : public EventTypeFinder {
+ public:
+ ETMTypeFinder() : EventTypeFinder(EventFinderType::ETM) {}
-static std::vector<EventFormat> ParseEventFormats(const std::string& evtdev_path) {
- std::vector<EventFormat> v;
- std::string formats_dirname = evtdev_path + "/format/";
- for (const auto& format_name : GetEntriesInDir(formats_dirname)) {
- std::string format_path = formats_dirname + format_name;
- std::string format_content;
- if (!android::base::ReadFileToString(format_path, &format_content)) {
- continue;
+ const EventType* FindType(const std::string& name) override {
+ if (name != kETMEventName) {
+ return nullptr;
}
+ return EventTypeFinder::FindType(name);
+ }
- // format files look like below (currently only 'config' is supported) :
- // # cat armv8_pmuv3/format/event
- // config:0-15
- int shift;
- if (sscanf(format_content.c_str(), "config:%d", &shift) != 1) {
- LOG(DEBUG) << "Invalid or unsupported event format: " << format_content;
- continue;
+ protected:
+ void LoadTypes() override {
+#if defined(__linux__)
+ std::unique_ptr<EventType> etm_type = ETMRecorder::GetInstance().BuildEventType();
+ if (etm_type) {
+ types_.emplace(std::move(*etm_type));
}
+#endif
+ }
+};
+
+class RawTypeFinder : public EventTypeFinder {
+ public:
+ RawTypeFinder() : EventTypeFinder(EventFinderType::RAW) {}
- v.emplace_back(EventFormat(format_name, "config", shift));
+ const EventType* AddType(EventType&& type) {
+ auto result = types_.emplace(std::move(type));
+ return &*(result.first);
}
- return v;
+
+ protected:
+ void LoadTypes() override {}
+};
+
+class ScopedTypeFinder : public EventTypeFinder {
+ public:
+ ScopedTypeFinder(std::set<EventType>&& types) : EventTypeFinder(EventFinderType::SCOPED) {
+ types_ = std::move(types);
+ }
+
+ protected:
+ void LoadTypes() override {}
+};
+
+EventTypeManager EventTypeManager::instance_;
+
+EventTypeManager::EventTypeManager() {
+ type_finders_.emplace_back(new BuiltinTypeFinder());
+ type_finders_.emplace_back(new TracepointSystemFinder());
+ type_finders_.emplace_back(new PMUTypeFinder());
+ type_finders_.emplace_back(new ETMTypeFinder());
+ type_finders_.emplace_back(new RawTypeFinder());
}
-static uint64_t MakeEventConfig(const std::string& event_str, std::vector<EventFormat>& formats) {
- uint64_t config = 0;
-
- // event files might have multiple terms, but usually have a term like:
- // # cat armv8_pmuv3/events/cpu_cycles
- // event=0x011
- for (auto& s : android::base::Split(event_str, ",")) {
- auto pos = s.find('=');
- if (pos == std::string::npos)
- continue;
-
- auto format = s.substr(0, pos);
- long val;
- if (!android::base::ParseInt(android::base::Trim(s.substr(pos+1)), &val)) {
- LOG(DEBUG) << "Invalid event format '" << s << "'";
- continue;
+EventTypeManager::~EventTypeManager() {}
+
+std::unique_ptr<EventTypeFinder>& EventTypeManager::GetFinder(EventFinderType type) {
+ for (auto& finder : type_finders_) {
+ if (finder->GetFinderType() == type) {
+ return finder;
}
+ }
+ LOG(FATAL) << "Failed to get EventTypeFinder";
+ __builtin_unreachable();
+}
- for (auto& f : formats) {
- if (f.name == format) {
- if (f.attr != "config") {
- LOG(DEBUG) << "cannot support other attribute: " << s;
- return ~0ULL;
- }
+RawTypeFinder& EventTypeManager::GetRawTypeFinder() {
+ return *static_cast<RawTypeFinder*>(GetFinder(EventFinderType::RAW).get());
+}
- config |= val << f.shift;
- break;
+TracepointSystemFinder& EventTypeManager::GetTracepointSystemFinder() {
+ return *static_cast<TracepointSystemFinder*>(GetFinder(EventFinderType::TRACEPOINT_SYSTEM).get());
+}
+
+bool EventTypeManager::ReadTracepointsFromFile(const std::string& filepath) {
+ std::string data;
+ if (!android::base::ReadFileToString(filepath, &data)) {
+ PLOG(ERROR) << "Failed to read " << filepath;
+ return false;
+ }
+ // Replace TracepointSystemFinder with TracepointStringFinder.
+ auto& finder = GetFinder(EventFinderType::TRACEPOINT_SYSTEM);
+ finder.reset(new TracepointStringFinder(std::move(data)));
+ return true;
+}
+
+bool EventTypeManager::WriteTracepointsToFile(const std::string& filepath) {
+ auto& tp_finder = GetTracepointSystemFinder();
+ std::string s = tp_finder.ToString();
+ if (!android::base::WriteStringToFile(s, filepath)) {
+ PLOG(ERROR) << "Failed to store tracepoint events";
+ return false;
+ }
+ return true;
+}
+
+bool EventTypeManager::ForEachType(const std::function<bool(const EventType&)>& callback) {
+ if (scoped_finder_) {
+ for (const auto& type : scoped_finder_->GetTypes()) {
+ if (!callback(type)) {
+ return false;
+ }
+ }
+ } else {
+ for (auto& finder : type_finders_) {
+ for (const auto& type : finder->GetTypes()) {
+ if (!callback(type)) {
+ return false;
+ }
}
}
}
- return config;
+ return true;
}
-static std::vector<EventType> GetPmuEventTypes() {
- std::vector<EventType> result;
- const std::string evtsrc_dirname = "/sys/bus/event_source/devices/";
- for (const auto& device_name : GetSubDirs(evtsrc_dirname)) {
- std::string evtdev_path = evtsrc_dirname + device_name;
- std::string type_path = evtdev_path + "/type";
- std::string type_content;
-
- if (!android::base::ReadFileToString(type_path, &type_content)) {
- LOG(DEBUG) << "cannot read event type: " << device_name;
- continue;
+const EventType* EventTypeManager::FindType(const std::string& name) {
+ if (scoped_finder_) {
+ return scoped_finder_->FindType(name);
+ }
+ for (auto& finder : type_finders_) {
+ if (auto type = finder->FindType(name)) {
+ return type;
}
- uint64_t type_id = strtoull(type_content.c_str(), NULL, 10);
+ }
+ return nullptr;
+}
- std::vector<EventFormat> formats = ParseEventFormats(evtdev_path);
+const EventType* EventTypeManager::AddRawType(const std::string& name) {
+ if (name.empty() || name[0] != 'r') {
+ return nullptr;
+ }
+ errno = 0;
+ char* end;
+ uint64_t config = strtoull(&name[1], &end, 16);
+ if (errno != 0 || *end != '\0') {
+ return nullptr;
+ }
+ auto& raw_finder = GetRawTypeFinder();
+ return raw_finder.AddType(EventType(name, PERF_TYPE_RAW, config, "", ""));
+}
- std::string events_dirname = evtdev_path + "/events/";
- for (const auto& event_name : GetEntriesInDir(events_dirname)) {
- std::string event_path = events_dirname + event_name;
- std::string event_content;
- if (!android::base::ReadFileToString(event_path, &event_content)) {
- LOG(DEBUG) << "cannot read event content in " << event_name;
- continue;
- }
+void EventTypeManager::RemoveProbeType(const std::string& name) {
+ GetTracepointSystemFinder().RemoveType(name);
+}
- uint64_t config = MakeEventConfig(event_content, formats);
- if (config == ~0ULL) {
- LOG(DEBUG) << "cannot handle config format in " << event_name;
- continue;
- }
- result.emplace_back(EventType(device_name + "/" + event_name + "/",
- type_id, config, "", ""));
- }
- }
- return result;
+void EventTypeManager::SetScopedFinder(std::unique_ptr<EventTypeFinder>&& finder) {
+ scoped_finder_ = std::move(finder);
}
std::vector<int> EventType::GetPmuCpumask() {
std::vector<int> empty_result;
- if (!IsPmuEvent())
- return empty_result;
+ if (!IsPmuEvent()) return empty_result;
std::string pmu = name.substr(0, name.find('/'));
std::string cpumask_path = "/sys/bus/event_source/devices/" + pmu + "/cpumask";
@@ -236,7 +458,10 @@ std::vector<int> EventType::GetPmuCpumask() {
LOG(DEBUG) << "cannot read cpumask content in " << pmu;
return empty_result;
}
- return GetCpusFromString(cpumask_content);
+ if (auto cpus = GetCpusFromString(cpumask_content); cpus) {
+ return std::vector<int>(cpus->begin(), cpus->end());
+ }
+ return empty_result;
}
std::string ScopedEventTypes::BuildString(const std::vector<const EventType*>& event_types) {
@@ -245,65 +470,39 @@ std::string ScopedEventTypes::BuildString(const std::vector<const EventType*>& e
if (!result.empty()) {
result.push_back('\n');
}
- result += android::base::StringPrintf("%s,%u,%" PRIu64, type->name.c_str(), type->type,
- type->config);
+ result +=
+ android::base::StringPrintf("%s,%u,%" PRIu64, type->name.c_str(), type->type, type->config);
}
return result;
}
ScopedEventTypes::ScopedEventTypes(const std::string& event_type_str) {
- saved_event_types_ = std::move(g_event_types);
- saved_etm_event_type_ = g_etm_event_type;
- g_event_types.clear();
+ std::set<EventType> event_types;
for (auto& s : android::base::Split(event_type_str, "\n")) {
std::string name = s.substr(0, s.find(','));
uint32_t type;
uint64_t config;
sscanf(s.c_str() + name.size(), ",%u,%" PRIu64, &type, &config);
- if (name == "cs-etm") {
- g_etm_event_type = type;
- }
- g_event_types.emplace(name, type, config, "", "");
+ event_types.emplace(name, type, config, "", "");
}
+ CHECK(EventTypeManager::Instance().GetScopedFinder() == nullptr);
+ EventTypeManager::Instance().SetScopedFinder(
+ std::make_unique<ScopedTypeFinder>(std::move(event_types)));
}
ScopedEventTypes::~ScopedEventTypes() {
- g_event_types = std::move(saved_event_types_);
- g_etm_event_type = saved_etm_event_type_;
-}
-
-const std::set<EventType>& GetAllEventTypes() {
- if (g_event_types.empty()) {
- g_event_types.insert(static_event_type_array.begin(), static_event_type_array.end());
- std::vector<EventType> tracepoint_array = GetTracepointEventTypes();
- g_event_types.insert(tracepoint_array.begin(), tracepoint_array.end());
- std::vector<EventType> pmu_array = GetPmuEventTypes();
- g_event_types.insert(pmu_array.begin(), pmu_array.end());
-#if defined(__linux__)
- std::unique_ptr<EventType> etm_type = ETMRecorder::GetInstance().BuildEventType();
- if (etm_type) {
- g_etm_event_type = etm_type->type;
- g_event_types.emplace(std::move(*etm_type));
- }
-#endif
- }
- return g_event_types;
+ CHECK(EventTypeManager::Instance().GetScopedFinder() != nullptr);
+ EventTypeManager::Instance().SetScopedFinder(nullptr);
}
const EventType* FindEventTypeByName(const std::string& name, bool report_error) {
- const auto& event_types = GetAllEventTypes();
- auto it = event_types.find(EventType(name, 0, 0, "", ""));
- if (it != event_types.end()) {
- return &*it;
- }
- if (!name.empty() && name[0] == 'r') {
- char* end;
- uint64_t config = strtoull(&name[1], &end, 16);
- if (end != &name[1] && *end == '\0') {
- auto result = g_event_types.emplace(name, PERF_TYPE_RAW, config, "", "");
- CHECK(result.second);
- return &*(result.first);
- }
+ const EventType* event_type = EventTypeManager::Instance().FindType(name);
+ if (event_type != nullptr) {
+ return event_type;
+ }
+ event_type = EventTypeManager::Instance().AddRawType(name);
+ if (event_type != nullptr) {
+ return event_type;
}
if (report_error) {
LOG(ERROR) << "Unknown event_type '" << name
@@ -387,5 +586,8 @@ std::unique_ptr<EventTypeAndModifier> ParseEventType(const std::string& event_ty
}
bool IsEtmEventType(uint32_t type) {
- return g_etm_event_type != 0 && type == g_etm_event_type;
+ const EventType* event_type = EventTypeManager::Instance().FindType(kETMEventName);
+ return (event_type != nullptr) && (event_type->type == type);
}
+
+} // namespace simpleperf