| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "garnet/lib/perfmon/events.h" |
| |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include "garnet/lib/perfmon/event-registry.h" |
| |
| namespace perfmon { |
| |
| // Tables of each model's registered events. |
| static internal::EventRegistry* g_model_events; |
| |
| namespace internal { |
| |
| EventRegistry* GetGlobalEventRegistry() { |
| if (g_model_events == nullptr) { |
| FX_VLOGS(2) << "Initializing model event registry"; |
| g_model_events = new internal::EventRegistry{}; |
| } |
| return g_model_events; |
| } |
| |
| } // namespace internal |
| |
| std::string GetDefaultModelName() { |
| std::string model_name = ""; |
| #ifdef __x86_64__ |
| model_name = "skylake"; |
| #endif |
| #ifdef __aarch64__ |
| model_name = "armv8"; |
| #endif |
| return model_name; |
| } |
| |
| void ModelEventManager::RegisterEvents(const char* model_name, const char* group_name, |
| const EventDetails* events, size_t count) { |
| internal::EventRegistry* registry = internal::GetGlobalEventRegistry(); |
| registry->RegisterEvents(model_name, group_name, events, count); |
| } |
| |
| std::unique_ptr<ModelEventManager> ModelEventManager::Create(const std::string& model_name) { |
| // For convenience, if no events have been registered yet, ensure the |
| // current arch's events are registered. |
| if (g_model_events == nullptr) { |
| internal::EventRegistry* registry = internal::GetGlobalEventRegistry(); |
| internal::RegisterCurrentArchEvents(registry); |
| } |
| auto iter = g_model_events->find(model_name); |
| if (iter == g_model_events->end()) { |
| return nullptr; |
| } |
| |
| auto model_event_manager = std::make_unique<ModelEventManager>( |
| ModelEventManager{model_name, &iter->second.arch_events, &iter->second.fixed_events, |
| &iter->second.model_events, &iter->second.misc_events}); |
| if (FX_VLOG_IS_ON(4)) { |
| model_event_manager->Dump(); |
| } |
| return model_event_manager; |
| } |
| |
| ModelEventManager::ModelEventManager(const std::string& model_name, const EventTable* arch_events, |
| const EventTable* fixed_events, const EventTable* model_events, |
| const EventTable* misc_events) |
| : model_name_(model_name), |
| arch_events_(arch_events), |
| fixed_events_(fixed_events), |
| model_events_(model_events), |
| misc_events_(misc_events) {} |
| |
| bool ModelEventManager::EventIdToEventDetails(EventId id, const EventDetails** out_details) const { |
| unsigned event = GetEventIdEvent(id); |
| const EventTable* events; |
| |
| switch (GetEventIdGroup(id)) { |
| case kGroupArch: |
| events = arch_events_; |
| break; |
| case kGroupFixed: |
| events = fixed_events_; |
| break; |
| case kGroupModel: |
| events = model_events_; |
| break; |
| case kGroupMisc: |
| events = misc_events_; |
| break; |
| default: |
| return false; |
| } |
| |
| if (event >= events->size()) { |
| return false; |
| } |
| const EventDetails* details = (*events)[event]; |
| if (details->id == 0) { |
| return false; |
| } |
| *out_details = details; |
| return true; |
| } |
| |
| // This just uses a linear search for now. |
| bool ModelEventManager::LookupEventByName(const char* group_name, const char* event_name, |
| const EventDetails** out_details) const { |
| const EventTable* events; |
| |
| if (strcmp(group_name, internal::kArchGroupName) == 0) { |
| events = arch_events_; |
| } else if (strcmp(group_name, internal::kFixedGroupName) == 0) { |
| events = fixed_events_; |
| } else if (strcmp(group_name, internal::kModelGroupName) == 0) { |
| events = model_events_; |
| } else if (strcmp(group_name, internal::kMiscGroupName) == 0) { |
| events = misc_events_; |
| } else { |
| return false; |
| } |
| |
| for (auto event : *events) { |
| if (event->id == 0) |
| continue; |
| if (strcmp(event->name, event_name) == 0) { |
| *out_details = event; |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| static void FillGroupTable(const char* name, const ModelEventManager::EventTable* events, |
| ModelEventManager::GroupTable* groups) { |
| groups->emplace_back(ModelEventManager::GroupEvents{name, {}}); |
| ModelEventManager::GroupEvents& group_events = groups->back(); |
| for (const auto& event : *events) { |
| if (event->id != 0) { |
| group_events.events.push_back(event); |
| } |
| } |
| } |
| |
| ModelEventManager::GroupTable ModelEventManager::GetAllGroups() const { |
| GroupTable groups; |
| |
| // Note: This makes copies of all the tables so that the result is not linked |
| // to this object's lifetime. It also allows us to remove empty slots |
| // (id == 0). |
| FillGroupTable(internal::kArchGroupName, arch_events_, &groups); |
| FillGroupTable(internal::kFixedGroupName, fixed_events_, &groups); |
| FillGroupTable(internal::kModelGroupName, model_events_, &groups); |
| FillGroupTable(internal::kMiscGroupName, misc_events_, &groups); |
| |
| return groups; |
| } |
| |
| void ModelEventManager::Dump() const { |
| printf("Dump of events for model %s\n", model_name_.c_str()); |
| DumpGroup(internal::kArchGroupName, arch_events_); |
| DumpGroup(internal::kFixedGroupName, fixed_events_); |
| DumpGroup(internal::kModelGroupName, model_events_); |
| DumpGroup(internal::kMiscGroupName, misc_events_); |
| } |
| |
| void ModelEventManager::DumpGroup(const char* name, const EventTable* events) const { |
| printf("Group %s\n", name); |
| for (const auto& event : *events) { |
| if (event->id != 0) { |
| printf(" %s\n", event->name); |
| } |
| } |
| } |
| |
| } // namespace perfmon |