mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 12:32:56 +01:00
base: High-level interface for hardware performance counters.
This commit is contained in:
87
repos/base-nova/src/lib/base/perf.cc
Normal file
87
repos/base-nova/src/lib/base/perf.cc
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* \brief Performance Counter infrastructure, NOVA-specific implemantation
|
||||||
|
* \author Michael Müller
|
||||||
|
* \date 2022-12-15
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <base/trace/perf.h>
|
||||||
|
|
||||||
|
#include <nova/syscall-generic.h>
|
||||||
|
#include <nova/syscalls.h>
|
||||||
|
#include <base/log.h>
|
||||||
|
|
||||||
|
unsigned long Genode::Trace::Performance_counter::private_freemask { 0xffff };
|
||||||
|
unsigned long Genode::Trace::Performance_counter::shared_freemask { 0xffff0000 };
|
||||||
|
|
||||||
|
void Genode::Trace::Performance_counter::_init_masks()
|
||||||
|
{
|
||||||
|
Nova::Hip::Cpu_desc::Vendor vendor = Nova::Hip::Cpu_desc::AMD;
|
||||||
|
if (vendor == Nova::Hip::Cpu_desc::AMD)
|
||||||
|
{
|
||||||
|
private_freemask = 0x3f; // 6 core performance counters
|
||||||
|
shared_freemask = 0x1f0000; // 5 L3 complex performance counters
|
||||||
|
}
|
||||||
|
else if (vendor == Nova::Hip::Cpu_desc::INTEL)
|
||||||
|
{
|
||||||
|
private_freemask = 0x7fff;
|
||||||
|
shared_freemask = 0x7fff0000; // 15 CBO performance counters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Genode::Trace::Performance_counter::setup(unsigned counter, uint64_t event, uint64_t mask, uint64_t flags)
|
||||||
|
{
|
||||||
|
Nova::mword_t evt = event;
|
||||||
|
Nova::mword_t msk = mask;
|
||||||
|
Nova::mword_t flg = flags;
|
||||||
|
Nova::uint8_t rc;
|
||||||
|
Nova::mword_t type = (counter >>4);
|
||||||
|
Nova::mword_t sel = type == Performance_counter::CORE ? counter : counter & 0xf;
|
||||||
|
|
||||||
|
if ((rc = (Nova::hpc_ctrl(Nova::HPC_SETUP, sel, type, evt, msk, flg))) != Nova::NOVA_OK)
|
||||||
|
throw Genode::Trace::Pfc_access_error(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Genode::Trace::Performance_counter::start(unsigned counter)
|
||||||
|
{
|
||||||
|
Nova::uint8_t rc;
|
||||||
|
Nova::mword_t type = (counter >> 4);
|
||||||
|
Nova::mword_t sel = type == Performance_counter::CORE ? counter : counter >>4;
|
||||||
|
|
||||||
|
if ((rc = Nova::hpc_start(sel, type)) != Nova::NOVA_OK)
|
||||||
|
throw Genode::Trace::Pfc_access_error(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Genode::Trace::Performance_counter::stop(unsigned counter)
|
||||||
|
{
|
||||||
|
Nova::uint8_t rc;
|
||||||
|
Nova::mword_t type = (counter >>4);
|
||||||
|
Nova::mword_t sel = type == Performance_counter::CORE ? counter : counter & 0xf;
|
||||||
|
|
||||||
|
if ((rc = Nova::hpc_stop(sel, type)) != Nova::NOVA_OK)
|
||||||
|
throw Genode::Trace::Pfc_access_error(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Genode::Trace::Performance_counter::reset(unsigned counter, unsigned val)
|
||||||
|
{
|
||||||
|
Nova::uint8_t rc;
|
||||||
|
Nova::mword_t type = (counter >>4);
|
||||||
|
Nova::mword_t sel = type == Performance_counter::CORE ? counter : counter & 0xf;
|
||||||
|
|
||||||
|
if ((rc = Nova::hpc_reset(sel, type, val)) != Nova::NOVA_OK)
|
||||||
|
throw Genode::Trace::Pfc_access_error(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
Genode::uint64_t Genode::Trace::Performance_counter::read(unsigned counter)
|
||||||
|
{
|
||||||
|
Nova::uint8_t rc;
|
||||||
|
Nova::mword_t value = 0;
|
||||||
|
Nova::mword_t type = (counter >>4);
|
||||||
|
Nova::mword_t sel = type == Performance_counter::CORE ? counter : counter & 0xf;
|
||||||
|
|
||||||
|
if ((rc = Nova::hpc_read(sel, type, value)) != Nova::NOVA_OK)
|
||||||
|
throw Genode::Trace::Pfc_access_error(rc);
|
||||||
|
|
||||||
|
Genode::log("Performance_counter::read = ", value);
|
||||||
|
return static_cast<Genode::uint64_t>(value);
|
||||||
|
}
|
||||||
93
repos/base/include/base/trace/perf.h
Normal file
93
repos/base/include/base/trace/perf.h
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* \brief Performance Counter infrastructure
|
||||||
|
* \author Michael Müller
|
||||||
|
* \date 2022-12-15
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <base/stdint.h>
|
||||||
|
|
||||||
|
namespace Genode { namespace Trace {
|
||||||
|
|
||||||
|
class Pfc_no_avail {
|
||||||
|
};
|
||||||
|
|
||||||
|
class Performance_counter
|
||||||
|
{
|
||||||
|
|
||||||
|
private:
|
||||||
|
static unsigned long private_freemask;
|
||||||
|
static unsigned long shared_freemask;
|
||||||
|
|
||||||
|
static unsigned _alloc(unsigned long *free_mask)
|
||||||
|
{
|
||||||
|
unsigned long current_mask, new_mask;
|
||||||
|
unsigned bit;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
current_mask = *free_mask;
|
||||||
|
bit = __builtin_ffsl(current_mask);
|
||||||
|
new_mask = current_mask & ~(1 << (bit - 1));
|
||||||
|
} while (!__atomic_compare_exchange(free_mask, ¤t_mask, &new_mask, true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED));
|
||||||
|
|
||||||
|
if (!bit) // Allocation failed
|
||||||
|
throw Pfc_no_avail();
|
||||||
|
|
||||||
|
return bit - 1; // number of the allocated counter
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _init_masks();
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef unsigned int Counter;
|
||||||
|
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
CORE = 0,
|
||||||
|
CACHE = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned acquire(Type type) {
|
||||||
|
return (type == Type::CORE) ? alloc_core() : alloc_cbo();
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned alloc_cbo() {
|
||||||
|
if (shared_freemask == 0xffff0000)
|
||||||
|
_init_masks();
|
||||||
|
return _alloc(&shared_freemask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned alloc_core() {
|
||||||
|
if (private_freemask == 0xffff)
|
||||||
|
_init_masks();
|
||||||
|
return _alloc(&private_freemask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void release(unsigned counter) {
|
||||||
|
bool core = static_cast<bool>(counter >> 4);
|
||||||
|
if (core)
|
||||||
|
private_freemask |= (1 << counter);
|
||||||
|
else
|
||||||
|
shared_freemask |= (1 << counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup(unsigned counter, Genode::uint64_t event, Genode::uint64_t mask, Genode::uint64_t flags);
|
||||||
|
static void start(unsigned counter);
|
||||||
|
static void stop(unsigned counter);
|
||||||
|
static void reset(unsigned counter, unsigned val=0);
|
||||||
|
static uint64_t read(unsigned counter);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Pfc_access_error {
|
||||||
|
private:
|
||||||
|
Genode::uint8_t _rc;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Pfc_access_error(uint8_t rc) : _rc(rc) {}
|
||||||
|
Genode::uint8_t error_code() { return _rc; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user