blob: 0e18f121f25299c9b48b2200fd9ee98b56610c78 [file] [log] [blame]
// 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/bin/cpuperf_provider/events.h"
#include <assert.h>
#include <zircon/device/cpu-trace/intel-pm.h>
#include <unordered_map>
#include "lib/fxl/logging.h"
namespace cpuperf_provider {
const EventDetails g_arch_event_details[] = {
#if IPM_API_VERSION == 0
#define DEF_ARCH_EVENT(symbol, ebx_bit, event, umask, flags, name) \
{ event, umask, flags, name },
#else
#define DEF_ARCH_EVENT(symbol, ebx_bit, event, umask, flags, name, description) \
{ event, umask, flags, name " (" description ")" },
#endif
#include <zircon/device/cpu-trace/intel-pm-events.inc>
};
const EventDetails g_skl_event_details[] = {
#if IPM_API_VERSION == 0
#define DEF_SKL_EVENT(symbol, event, umask, flags, name) \
{ event, umask, flags, name },
#include <zircon/device/cpu-trace/intel-pm-events.inc>
#else
#define DEF_SKL_EVENT(symbol, event, umask, flags, name, description) \
{ event, umask, flags, name " (" description ")" },
#include <zircon/device/cpu-trace/skylake-pm-events.inc>
#endif
};
using EventSelectMap = std::unordered_map<uint32_t, const EventDetails*>;
static EventSelectMap* g_arch_event_select_map;
static EventSelectMap* g_skl_event_select_map;
uint32_t MakeEventKey(const EventDetails& d) {
FXL_DCHECK(d.event < (1 << IA32_PERFEVTSEL_EVENT_SELECT_LEN));
FXL_DCHECK(d.umask < (1 << IA32_PERFEVTSEL_UMASK_LEN));
FXL_DCHECK((d.flags & IPM_REG_FLAG_CMSK_MASK) < (1 << IA32_PERFEVTSEL_CMASK_LEN));
uint32_t key = ((d.event << IA32_PERFEVTSEL_EVENT_SELECT_SHIFT) |
(d.umask << IA32_PERFEVTSEL_UMASK_SHIFT) |
((d.flags & IPM_REG_FLAG_CMSK_MASK) << IA32_PERFEVTSEL_CMASK_SHIFT) |
(!!(d.flags & IPM_REG_FLAG_ANYT) << IA32_PERFEVTSEL_ANY_SHIFT));
return key;
}
static void InitializeEventSelectMap(const EventDetails* details, size_t count,
EventSelectMap* map) {
for (size_t i = 0; i < count; ++i) {
const EventDetails* d = &details[i];
uint32_t key = MakeEventKey(*d);
FXL_DCHECK(map->count(key) == 0);
(*map)[key] = d;
}
}
// Call this from main, before anything that needs to use
// |g_*_event_select_map|.
void InitializeEventSelectMaps() {
g_arch_event_select_map = new EventSelectMap();
InitializeEventSelectMap(g_arch_event_details, countof(g_arch_event_details),
g_arch_event_select_map);
// TODO(dje): For now assume skylake/kabylake.
g_skl_event_select_map = new EventSelectMap();
InitializeEventSelectMap(g_skl_event_details, countof(g_skl_event_details),
g_skl_event_select_map);
}
bool EventSelectToEventDetails(uint64_t event_select,
const EventDetails** details) {
uint32_t key = event_select & (IA32_PERFEVTSEL_EVENT_SELECT_MASK |
IA32_PERFEVTSEL_UMASK_MASK |
IA32_PERFEVTSEL_CMASK_MASK |
IA32_PERFEVTSEL_ANY_MASK);
if (g_arch_event_select_map->count(key)) {
*details = (*g_arch_event_select_map)[key];
return true;
}
if (g_skl_event_select_map->count(key)) {
*details = (*g_skl_event_select_map)[key];
return true;
}
return false;
}
const EventDetails* GetFixedEventDetails(int n) {
enum {
#if IPM_API_VERSION == 0
#define DEF_ARCH_EVENT(symbol, ebx_bit, event, umask, flags, name) \
EVENT_ ## symbol,
#else
#define DEF_ARCH_EVENT(symbol, ebx_bit, event, umask, flags, name, description) \
EVENT_ ## symbol,
#endif
#include <zircon/device/cpu-trace/intel-pm-events.inc>
};
switch (n) {
case 0:
return &g_arch_event_details[EVENT_ARCH_INSTRUCTIONS_RETIRED];
case 1:
return &g_arch_event_details[EVENT_ARCH_UNHALTED_CORE_CYCLES];
case 2:
return &g_arch_event_details[EVENT_ARCH_UNHALTED_REFERENCE_CYCLES];
default:
assert(0);
__UNREACHABLE;
}
}
} // namespace cpuperf_provider