blob: bc20039157736c23277013923d31752d1683d25d [file] [log] [blame] [edit]
// 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