44#include "debug/Checkpoint.hh"
45#include "debug/PMUVerbose.hh"
48#include "params/ArmPMU.hh"
75 DPRINTF(PMUVerbose,
"Initializing the PMU.\n");
78 fatal(
"The PMU can only accept 31 counters, %d counters requested.\n",
82 for (
const auto& [key, value] :
p.statCounters) {
86 warn_if(!
p.interrupt,
"ARM PMU: No interrupt specified, interrupt " \
87 "delivery disabled.\n");
107 const auto &pmu_params =
static_cast<const ArmPMUParams &
>(
params());
109 if (pmu_params.interrupt)
110 interrupt = pmu_params.interrupt->get(tc);
117 DPRINTF(PMUVerbose,
"PMU: Adding SW increment event with id '0x%x'\n",
id);
122 "Trying to add a software increment event with multiple"
123 "IDs. This is not supported.\n");
128 "been previously defined\n",
id);
141 DPRINTF(PMUVerbose,
"PMU: Adding Probe Driven event with id '0x%x'"
142 "as probe %s:%s\n",
id, obj->
name(), probe_name);
144 std::shared_ptr<RegularEvent>
event;
145 auto event_entry =
eventMap.find(
id);
146 if (event_entry ==
eventMap.end()) {
149 event = std::make_shared<RegularEvent>(
id, pmu_stats);
152 event = std::dynamic_pointer_cast<RegularEvent>(event_entry->second);
153 fatal_if(!
event,
"Event with id %d is not probe driven\n",
id);
155 event->addMicroarchitectureProbe(obj, probe_name);
167 }
else if (
id > 0x20 &&
id < 0x40) {
169 }
else if (
id >= 0x4000 &&
id < 0x4020) {
170 reg_pmceid0 |= ((uint64_t)1) << (
id - 0x4000 + 32);
171 }
else if (
id >= 0x4020 &&
id < 0x4040) {
172 reg_pmceid1 |= ((uint64_t)1) << (
id - 0x4020 + 32);
201 if (
auto stat_event =
getEvent(event_id); stat_event) {
202 stat_event->enable();
210 DPRINTF(PMUVerbose,
"setMiscReg(%s, 0x%x)\n",
271 DPRINTF(PMUVerbose,
"Setting PMCCFILTR: 0x%x\n",
val);
278 DPRINTF(PMUVerbose,
"Setting counter type: "
279 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
320 warn(
"Not doing anything for write to miscreg %s\n",
328 DPRINTF(PMUVerbose,
"readMiscReg(%s): 0x%x\n",
417 warn(
"Not doing anything for read from miscreg %s\n",
425 DPRINTF(PMUVerbose,
"Set Control Reg 0x%08x.\n",
val);
428 DPRINTF(PMUVerbose,
"PMU reset all events to zero.\n");
433 DPRINTF(PMUVerbose,
"PMU reset cycle counter to zero.\n");
461 inform(
"Exiting simulation: PMU enable detected");
464 inform(
"Exiting simulation: PMU disable detected");
467 }
else if (check_reset &&
reg_pmcr.p) {
468 inform(
"Exiting simulation: PMU reset detected");
476 const bool global_enable(
reg_pmcr.e);
552 panic(
"Unsupported probe kind for event %s", probe->
getName());
570 const bool secure(
pmu.isa->inSecureState());
586 panic(
"Unexpected execution level in PMU::isFiltered.\n");
598 "detaching event %d not currently attached to any event"
620 debugCounter(
"attempted to get value from a counter without"
621 " an associated event\n");
635 debugCounter(
"attempted to set value from a counter without"
636 " an associated event\n");
644 DPRINTF(PMUVerbose,
"updateCounter(%i): Disabling counter\n",
649 DPRINTF(PMUVerbose,
"updateCounter(%i): Enable event id 0x%x\n",
653 if (sourceEvent ==
eventMap.end()) {
654 warn(
"Can't enable PMU counter of type '0x%x': "
655 "No such event type.\n", ctr.
eventId);
658 ctr.
attach(sourceEvent->second);
675 warn_once(
"Can't change counter value: Counter %i does not exist.\n",
701 DPRINTF(PMUVerbose,
"Set Event [%d] = 0x%08x\n",
id,
val);
703 warn_once(
"Can't change counter type: Counter %i does not exist.\n",
716 if (
id !=
PMCCNTR && old_event_id !=
val.evtCount) {
726 const bool int_new = new_val != 0;
729 if (int_old && !int_new) {
740 inform(
"Exiting simulation: PMU interrupt detected");
744 DPRINTF(PMUVerbose,
"Delivering PMU interrupt.\n");
747 warn_once(
"Dropping PMU interrupt as no interrupt has "
756 DPRINTF(PMUVerbose,
"Clearing PMU interrupt.\n");
759 warn_once(
"Dropping PMU interrupt as no interrupt has "
767 DPRINTF(Checkpoint,
"Serializing Arm PMU\n");
788 DPRINTF(Checkpoint,
"Unserializing Arm PMU\n");
816std::shared_ptr<PMU::PMUEvent>
819 auto entry =
eventMap.find(eventId);
822 warn(
"event %d does not exist\n", eventId);
825 return entry->second;
848 uint64_t value_until_overflow;
850 value_until_overflow = UINT64_MAX -
value;
852 value_until_overflow = UINT32_MAX - (uint32_t)
value;
856 return value_until_overflow;
865 if (delta > value_until_overflow) {
874 pmu.raiseInterrupt();
878 return value_until_overflow - delta + 1;
885 if (
val & (0x1 << counter->getCounterId())) {
894 auto params =
static_cast<const ArmPMUParams&
>(
pmu->params());
895 for (
const auto& [key,
val] :
params.statCounters) {
896 registerEvent(key, val.c_str());
903 map.emplace(std::piecewise_construct,
904 std::forward_as_tuple(
id),
905 std::forward_as_tuple(
916 if (
auto it =
map.find(
id); it !=
map.end()) {
919 panic(
"Couldn't increment event %d stat counter",
id);
#define DPRINTFS(x, s,...)
Base class for ARM GIC implementations.
void write(uint64_t val)
write on the sw increment register inducing an increment of the counters with this event selected acc...
std::shared_ptr< PMUEvent > getEvent(EventTypeId eventId)
Obtain the event of a given id.
void regProbeListeners() override
Register probe listeners for this object.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void setControlReg(PMCR_t val)
PMCR write handling.
void raiseInterrupt()
Deliver a PMU interrupt to the GIC.
void addEventProbe(EventTypeId id, SimObject *obj, const char *name)
PMCR_t reg_pmcr_conf
Constant (configuration-dependent) part of the PMCR.
RegVal readMiscReg(int misc_reg) override
Read a register within the PMU.
RegVal reg_pmcnten
Performance Monitor Count Enable Register.
void clearInterrupt()
Clear a PMU interrupt.
uint64_t maximumCounterCount
The number of regular event counters.
static const RegVal reg_pmcr_wr_mask
PMCR write mask when accessed from the guest.
bool isFiltered(const CounterState &ctr) const
Check if a counter's settings allow it to be counted.
PMEVTYPER_t getCounterTypeRegister(CounterId id) const
Get the type and filter settings of a counter (PMEVTYPER)
unsigned clock_remainder
Remainder part when the clock counter is divided by 64.
void updateAllCounters()
Call updateCounter() for each counter in the PMU if the counter's state has changed.
void resetEventCounts()
Reset all event counters excluding the cycle counter to zero.
void setOverflowStatus(RegVal new_val)
Used for writing the Overflow Flag Status Register (SET/CLR)
PMSELR_t reg_pmselr
Performance Monitor Selection Register.
std::map< EventTypeId, std::shared_ptr< PMUEvent > > eventMap
List of event types supported by this PMU.
bool pmuEnabled
Is there an enabled counter.
void addSoftwareIncrementEvent(EventTypeId id)
static const CounterId PMCCNTR
Cycle Count Register Number.
void setThreadContext(ThreadContext *tc) override
std::vector< CounterState > counters
State of all general-purpose counters supported by PMU.
void setCounterTypeRegister(CounterId id, PMEVTYPER_t type)
Set the type and filter settings of a performance counter (PMEVTYPER)
void drainResume() override
Resume execution after a successful drain.
PMU(const ArmPMUParams &p)
RegVal readMiscRegInt(int misc_reg)
std::set< EventTypeId > statCounters
Determine whether we merge event counting with the stats framework.
void pmuExitEvent(bool check_reset)
Checks if a PMU exit event needs to be generated.
void setMiscReg(int misc_reg, RegVal val) override
Set a register within the PMU.
CounterState cycleCounter
State of the cycle counter.
uint64_t reg_pmceid0
Performance counter ID register.
const EventTypeId cycleCounterEventId
The id of the counter hardwired to the cpu cycle counter.
bool isValidCounter(CounterId id) const
Is this a valid counter ID?
PMCR_t reg_pmcr
Performance Monitor Control Register.
RegVal reg_pmovsr
Performance Monitor Overflow Status Register.
std::underlying_type_t< enums::EventTypeId > EventTypeId
ArmInterruptPin * interrupt
Performance monitor interrupt number.
void registerEvent(EventTypeId id)
CounterState & getCounter(CounterId id)
Return the state of a counter.
bool use64bitCounters
Determine whether to use 64-bit or 32-bit counters.
std::shared_ptr< SWIncrementEvent > swIncrementEvent
The event that implements the software increment.
uint64_t getCounterValue(CounterId id) const
Get the value of a performance counter.
bool exitOnPMUInterrupt
Exit simloop on PMU interrupt.
gem5::ArmISA::PMU::Stats stats
void setCounterValue(CounterId id, uint64_t val)
Set the value of a performance counter.
RegVal reg_pminten
Performance Monitor Interrupt Enable Register.
void updateCounter(CounterState &ctr)
Depending on counter configuration, add or remove the probes driving the counter.
void serialize(CheckpointOut &cp) const override
Serialize an object.
const bool exitOnPMUControl
Exit simloop on PMU reset or disable.
virtual std::string name() const
ProbeManager is a conduit class that lives on each SimObject, and is used to match up probe listeners...
ProbeListenerPtr< Listener > connect(Args &&...args)
ProbePoint * getFirstProbePoint(std::string_view point_name) const
ProbePointArg generates a point for the class of Arg.
ProbePoint base class; again used to simplify use of ProbePoints in containers and used as to define ...
const std::string & getName() const
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual ContextID contextId() const =0
This module implements the global system counter and the local per-CPU architected timers as specifie...
#define panic(...)
This implements a cprintf based panic() function.
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
#define fatal(...)
This implements a cprintf based fatal() function.
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
#define UNSERIALIZE_OPT_SCALAR(scalar)
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
const Params & params() const
SimObject(const Params &p)
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
@ MISCREG_PMXEVTYPER_PMCCFILTR
int unflattenMiscReg(int reg)
const char *const miscRegName[]
ProbePointArg< uint64_t > PMU
PMU probe point.
Copyright (c) 2024 Arm Limited All rights reserved.
std::ostream CheckpointOut
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
void exitSimLoop(const std::string &message, int exit_code, Tick when, Tick repeat, bool serialize)
The "old style" exitSimLoop functions.
std::string csprintf(const char *format, const Args &...args)
#define UNSERIALIZE_SCALAR(scalar)
#define SERIALIZE_SCALAR(scalar)
State of a counter within the PMU.
bool resetValue
Flag keeping track if the counter has been reset.
void attach(const std::shared_ptr< PMUEvent > &event)
Attach this counter to an event.
PMEVTYPER_t filter
Filtering settings (evtCount is unused)
uint64_t value
Current value of the counter.
bool overflow64
Is this a 64-bit counter?
uint64_t counterId
id of the counter instance
void detach()
Detach the counter from its event.
EventTypeId eventId
Counter event ID.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
uint64_t getCounterId() const
Obtain the counter id.
uint64_t getValue() const
rReturn the counter value
std::shared_ptr< PMUEvent > sourceEvent
PmuEvent currently in use (if any)
bool enabled
Is the counter enabled?
uint64_t add(uint64_t delta)
Add an event count to the counter and check for overflow.
void serialize(CheckpointOut &cp) const override
Serialize an object.
void debugCounter(const char *mainString, Args &...args) const
void setValue(uint64_t val)
overwrite the value of the counter
void attachEvent(PMU::CounterState *user)
attach this event to a given counter
virtual void enable()=0
Enable the current event.
virtual void disable()=0
Disable the current event.
Stats *const pmuStats
True is event is reported as a stat.
std::set< PMU::CounterState * > userCounters
set of counters using this event
virtual void updateAttachedCounters()
Method called immediately before a counter access in order for the associated event to update its sta...
void detachEvent(PMU::CounterState *user)
detach this event from a given counter
virtual void increment(const uint64_t val)
notify an event increment of val units, all the attached counters' value is incremented by val units.
void notify(const uint64_t &val) override
RegularEvent * parentEvent
std::set< EventTypeEntry > microArchitectureEventSet
The set of events driving the event value.
void enable() override
Enable the current event.
void disable() override
Disable the current event.
std::vector< ProbeListenerPtr<> > attachedProbePointList
Set of probe listeners tapping onto each of the input micro-arch events which compose this pmu event.
void registerEvent(EventTypeId id, const char *stat_name)
void add(EventTypeId id, uint64_t value)
Increment the map[id] stat by value.
std::unordered_map< EventTypeId, statistics::Scalar > map