summaryrefslogtreecommitdiff
path: root/src/arch
diff options
context:
space:
mode:
authorJose Marinho <jose.marinho@arm.com>2017-09-26 14:33:49 +0100
committerAndreas Sandberg <andreas.sandberg@arm.com>2017-11-21 17:09:18 +0000
commit4bb053c3d2a4f7563eca8761f859458f8cc47a05 (patch)
tree5535ae7c39957c21327b4e0f58baf7483482a1e1 /src/arch
parent69ac4aced0930c37d5523e5b56db8759bbc2bcc8 (diff)
downloadgem5-4bb053c3d2a4f7563eca8761f859458f8cc47a05.tar.xz
arch-arm: ArmPMU refactor
Change the definition of PMU events in order to integrate events not cannot easily be represented by probe points. The software increment event is now defined as a special type with its separate implementation in pmu.cc and pmu.hh. Change-Id: I43874b9641bf38c54f6ba2c26386542b6a73e282 Signed-off-by: Jose Marinho <jose.marinho@arm.com> Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com> Reviewed-on: https://gem5-review.googlesource.com/5764 Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/arm/ArmPMU.py81
-rw-r--r--src/arch/arm/pmu.cc315
-rw-r--r--src/arch/arm/pmu.hh296
3 files changed, 497 insertions, 195 deletions
diff --git a/src/arch/arm/ArmPMU.py b/src/arch/arm/ArmPMU.py
index 83c7dd48e..a87c20b4a 100644
--- a/src/arch/arm/ArmPMU.py
+++ b/src/arch/arm/ArmPMU.py
@@ -43,38 +43,61 @@ from m5.params import *
from m5.params import isNullPointer
from m5.proxy import *
+class ProbeEvent(object):
+ def __init__(self, pmu, _eventId, obj, *listOfNames):
+ self.obj = obj
+ self.names = listOfNames
+ self.eventId = _eventId
+ self.pmu = pmu
+
+ def register(self):
+ if self.obj:
+ for name in self.names:
+ self.pmu.getCCObject().addEventProbe(self.eventId,
+ self.obj.getCCObject(), name)
+
+class SoftwareIncrement(object):
+ def __init__(self,pmu, _eventId):
+ self.eventId = _eventId
+ self.pmu = pmu
+
+ def register(self):
+ self.pmu.getCCObject().addSoftwareIncrementEvent(self.eventId)
+
+ARCH_EVENT_CORE_CYCLES = 0x11
+
class ArmPMU(SimObject):
+
type = 'ArmPMU'
cxx_class = 'ArmISA::PMU'
cxx_header = 'arch/arm/pmu.hh'
cxx_exports = [
PyBindMethod("addEventProbe"),
+ PyBindMethod("addSoftwareIncrementEvent"),
]
- # To prevent cycles in the configuration hierarchy, we don't keep
- # a list of supported events as a configuration param. Instead, we
- # keep them in a local list and register them using the
- # addEventProbe interface when other SimObjects register their
- # probe listeners.
- _deferred_event_types = []
+ _events = None
+
+ def addEvent(self, newObject):
+ if not (isinstance(newObject, ProbeEvent)
+ or isinstance(newObject, SoftwareIncrement)):
+ raise TypeError("argument must be of ProbeEvent or "
+ "SoftwareIncrement type")
+
+ if not self._events:
+ self._events = []
+
+ self._events.append(newObject)
+
# Override the normal SimObject::regProbeListeners method and
# register deferred event handlers.
def regProbeListeners(self):
- for event_id, obj, name in self._deferred_event_types:
- self.getCCObject().addEventProbe(event_id, obj.getCCObject(), name)
+ for event in self._events:
+ event.register()
self.getCCObject().regProbeListeners()
- def addEventProbe(self, event_id, obj, *args):
- """Add a probe-based event to the PMU if obj is not None."""
-
- if obj is None:
- return
-
- for name in args:
- self._deferred_event_types.append((event_id, obj, name))
-
def addArchEvents(self,
cpu=None,
itb=None, dtb=None,
@@ -95,25 +118,28 @@ class ArmPMU(SimObject):
bpred = cpu.branchPred if cpu and not isNullPointer(cpu.branchPred) \
else None
+ self.addEvent(SoftwareIncrement(self,0x00))
# 0x01: L1I_CACHE_REFILL
- self.addEventProbe(0x02, itb, "Refills")
+ self.addEvent(ProbeEvent(self,0x02, itb, "Refills"))
# 0x03: L1D_CACHE_REFILL
# 0x04: L1D_CACHE
- self.addEventProbe(0x05, dtb, "Refills")
- self.addEventProbe(0x06, cpu, "RetiredLoads")
- self.addEventProbe(0x07, cpu, "RetiredStores")
- self.addEventProbe(0x08, cpu, "RetiredInsts")
+ self.addEvent(ProbeEvent(self,0x05, dtb, "Refills"))
+ self.addEvent(ProbeEvent(self,0x06, cpu, "RetiredLoads"))
+ self.addEvent(ProbeEvent(self,0x07, cpu, "RetiredStores"))
+ self.addEvent(ProbeEvent(self,0x08, cpu, "RetiredInsts"))
# 0x09: EXC_TAKEN
# 0x0A: EXC_RETURN
# 0x0B: CID_WRITE_RETIRED
- self.addEventProbe(0x0C, cpu, "RetiredBranches")
+ self.addEvent(ProbeEvent(self,0x0C, cpu, "RetiredBranches"))
# 0x0D: BR_IMMED_RETIRED
# 0x0E: BR_RETURN_RETIRED
# 0x0F: UNALIGEND_LDST_RETIRED
- self.addEventProbe(0x10, bpred, "Misses")
- self.addEventProbe(0x11, cpu, "ActiveCycles")
- self.addEventProbe(0x12, bpred, "Branches")
- self.addEventProbe(0x13, cpu, "RetiredLoads", "RetiredStores")
+ self.addEvent(ProbeEvent(self,0x10, bpred, "Misses"))
+ self.addEvent(ProbeEvent(self, ARCH_EVENT_CORE_CYCLES, cpu,
+ "ActiveCycles"))
+ self.addEvent(ProbeEvent(self,0x12, bpred, "Branches"))
+ self.addEvent(ProbeEvent(self,0x13, cpu, "RetiredLoads",
+ "RetiredStores"))
# 0x14: L1I_CACHE
# 0x15: L1D_CACHE_WB
# 0x16: L2D_CACHE
@@ -144,6 +170,7 @@ class ArmPMU(SimObject):
# 0x2F: L2D_TLB
# 0x30: L2I_TLB
+ cycleEventId = Param.Int(ARCH_EVENT_CORE_CYCLES, "Cycle event id")
platform = Param.Platform(Parent.any, "Platform this device is part of.")
eventCounters = Param.Int(31, "Number of supported PMU counters")
pmuInterrupt = Param.Int(68, "PMU GIC interrupt number")
diff --git a/src/arch/arm/pmu.cc b/src/arch/arm/pmu.cc
index baf0d1948..0bdae4936 100644
--- a/src/arch/arm/pmu.cc
+++ b/src/arch/arm/pmu.cc
@@ -37,6 +37,7 @@
* Authors: Dam Sunwoo
* Matt Horsnell
* Andreas Sandberg
+ * Jose Marinho
*/
#include "arch/arm/pmu.hh"
@@ -48,6 +49,7 @@
#include "debug/Checkpoint.hh"
#include "debug/PMUVerbose.hh"
#include "dev/arm/base_gic.hh"
+#include "dev/arm/generic_timer.hh"
#include "dev/arm/realview.hh"
#include "params/ArmPMU.hh"
@@ -61,16 +63,19 @@ PMU::PMU(const ArmPMUParams *p)
reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
reg_pmceid0(0),reg_pmceid1(0),
clock_remainder(0),
- counters(p->eventCounters),
+ maximumCounterCount(p->eventCounters),
+ cycleCounter(*this, maximumCounterCount),
+ cycleCounterEventId(p->cycleEventId),
+ swIncrementEvent(nullptr),
reg_pmcr_conf(0),
pmuInterrupt(p->pmuInterrupt),
platform(p->platform)
{
DPRINTF(PMUVerbose, "Initializing the PMU.\n");
- if (p->eventCounters > 31) {
+ if (maximumCounterCount > 31) {
fatal("The PMU can only accept 31 counters, %d counters requested.\n",
- p->eventCounters);
+ maximumCounterCount);
}
/* Setup the performance counter ID registers */
@@ -88,12 +93,56 @@ PMU::~PMU()
}
void
+PMU::addSoftwareIncrementEvent(unsigned int id)
+{
+ auto old_event = eventMap.find(id);
+ DPRINTF(PMUVerbose, "PMU: Adding SW increment event with id '0x%x'\n", id);
+
+ if (swIncrementEvent) {
+ fatal_if(old_event == eventMap.end() ||
+ old_event->second != swIncrementEvent,
+ "Trying to add a software increment event with multiple"
+ "IDs. This is not supported.\n");
+ return;
+ }
+
+ fatal_if(old_event != eventMap.end(), "An event with id %d has "
+ "been previously defined\n", id);
+
+ swIncrementEvent = new SWIncrementEvent();
+ eventMap[id] = swIncrementEvent;
+ registerEvent(id);
+}
+
+void
PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name)
{
- DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n",
- id, obj->name(), probe_name);
- pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name)));
+ DPRINTF(PMUVerbose, "PMU: Adding Probe Driven event with id '0x%x'"
+ "as probe %s:%s\n",id, obj->name(), probe_name);
+
+ RegularEvent *event = nullptr;
+ auto event_entry = eventMap.find(id);
+ if (event_entry == eventMap.end()) {
+
+ event = new RegularEvent();
+ eventMap[id] = event;
+
+ } else {
+ event = dynamic_cast<RegularEvent*>(event_entry->second);
+ if (!event) {
+ fatal("Event with id %d is not probe driven\n", id);
+ }
+ }
+ event->addMicroarchitectureProbe(obj, probe_name);
+
+ registerEvent(id);
+
+}
+
+void
+PMU::registerEvent(uint32_t id)
+{
// Flag the event as available in the corresponding PMCEID register if it
// is an architected event.
if (id < 0x20) {
@@ -115,6 +164,22 @@ PMU::drainResume()
}
void
+PMU::regProbeListeners()
+{
+
+ // at this stage all probe configurations are done
+ // counters can be configured
+ for (uint32_t index = 0; index < maximumCounterCount-1; index++) {
+ counters.emplace_back(*this, index);
+ }
+
+ PMUEvent *event = getEvent(cycleCounterEventId);
+ panic_if(!event, "core cycle event is not present\n");
+ cycleCounter.enabled = true;
+ cycleCounter.attach(event);
+}
+
+void
PMU::setMiscReg(int misc_reg, MiscReg val)
{
DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
@@ -145,18 +210,14 @@ PMU::setMiscReg(int misc_reg, MiscReg val)
case MISCREG_PMSWINC_EL0:
case MISCREG_PMSWINC:
- for (int i = 0; i < counters.size(); ++i) {
- CounterState &ctr(getCounter(i));
- if (ctr.enabled && (val & (1 << i))
- && ctr.eventId == ARCH_EVENT_SW_INCR ) {
- ++ctr.value;
- }
+ if (swIncrementEvent) {
+ swIncrementEvent->write(val);
}
- break;
+ return;
case MISCREG_PMCCNTR_EL0:
case MISCREG_PMCCNTR:
- cycleCounter.value = val;
+ cycleCounter.setValue(val);
return;
case MISCREG_PMSELR_EL0:
@@ -278,10 +339,10 @@ PMU::readMiscRegInt(int misc_reg)
return reg_pmceid1 & 0xFFFFFFFF;
case MISCREG_PMCCNTR_EL0:
- return cycleCounter.value;
+ return cycleCounter.getValue();
case MISCREG_PMCCNTR:
- return cycleCounter.value & 0xFFFFFFFF;
+ return cycleCounter.getValue() & 0xFFFFFFFF;
case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
@@ -295,8 +356,11 @@ PMU::readMiscRegInt(int misc_reg)
case MISCREG_PMXEVTYPER:
return getCounterTypeRegister(reg_pmselr.sel);
- case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
- return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF;
+ case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: {
+ return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) &
+ 0xFFFFFFFF;
+
+ }
case MISCREG_PMXEVCNTR_EL0:
case MISCREG_PMXEVCNTR:
@@ -334,7 +398,7 @@ PMU::setControlReg(PMCR_t val)
if (val.c) {
DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
- cycleCounter.value = 0;
+ cycleCounter.setValue(0);
}
// Reset the clock remainder if divide by 64-mode is toggled.
@@ -355,25 +419,74 @@ PMU::updateAllCounters()
const bool enable(global_enable && (reg_pmcnten & (1 << i)));
if (ctr.enabled != enable) {
ctr.enabled = enable;
- updateCounter(i, ctr);
+ updateCounter(ctr);
}
}
const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
if (cycleCounter.enabled != ccntr_enable) {
cycleCounter.enabled = ccntr_enable;
- updateCounter(PMCCNTR, cycleCounter);
+ updateCounter(cycleCounter);
+ }
+}
+
+void
+PMU::PMUEvent::attachEvent(PMU::CounterState *user)
+{
+ if (userCounters.empty()) {
+ enable();
}
+ userCounters.insert(user);
+ updateAttachedCounters();
+}
+
+void
+PMU::PMUEvent::increment(const uint64_t val)
+{
+ for (auto& counter: userCounters) {
+ counter->add(val);
+ }
+}
+
+void
+PMU::PMUEvent::detachEvent(PMU::CounterState *user)
+{
+ userCounters.erase(user);
+
+ if (userCounters.empty()) {
+ disable();
+ }
+}
+
+void
+PMU::RegularEvent::RegularProbe::notify(const uint64_t &val)
+{
+ parentEvent->increment(val);
+}
+
+void
+PMU::RegularEvent::enable()
+{
+ for (auto& subEvents: microArchitectureEventSet) {
+ attachedProbePointList.emplace_back(
+ new RegularProbe(this, subEvents.first, subEvents.second));
+ }
+}
+
+void
+PMU::RegularEvent::disable()
+{
+ attachedProbePointList.clear();
}
bool
-PMU::isFiltered(const CounterState &ctr) const
+PMU::CounterState::isFiltered() const
{
- assert(isa);
+ assert(pmu.isa);
- const PMEVTYPER_t filter(ctr.filter);
- const SCR scr(isa->readMiscRegNoEffect(MISCREG_SCR));
- const CPSR cpsr(isa->readMiscRegNoEffect(MISCREG_CPSR));
+ const PMEVTYPER_t filter(this->filter);
+ const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR));
+ const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR));
const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode));
const bool secure(inSecureState(scr, cpsr));
@@ -396,60 +509,69 @@ PMU::isFiltered(const CounterState &ctr) const
}
void
-PMU::handleEvent(CounterId id, uint64_t delta)
+PMU::CounterState::detach()
{
- CounterState &ctr(getCounter(id));
- const bool overflowed(reg_pmovsr & (1 << id));
+ if (sourceEvent) {
+ sourceEvent->detachEvent(this);
+ sourceEvent = nullptr;
+ } else {
+ debugCounter("detaching event not currently attached"
+ " to any event\n");
+ }
+}
- if (isFiltered(ctr))
- return;
+void
+PMU::CounterState::attach(PMUEvent* event)
+{
+ value = 0;
+ sourceEvent = event;
+ sourceEvent->attachEvent(this);
+}
- // Handle the "count every 64 cycles" mode
- if (id == PMCCNTR && reg_pmcr.d) {
- clock_remainder += delta;
- delta = (clock_remainder >> 6);
- clock_remainder &= 63;
+uint64_t
+PMU::CounterState::getValue() const
+{
+ if (sourceEvent) {
+ sourceEvent->updateAttachedCounters();
+ } else {
+ debugCounter("attempted to get value from a counter without"
+ " an associated event\n");
}
+ return value;
+}
- // Add delta and handle (new) overflows
- if (ctr.add(delta) && !overflowed) {
- DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id);
- reg_pmovsr |= (1 << id);
- // Deliver a PMU interrupt if interrupt delivery is enabled
- // for this counter.
- if (reg_pminten & (1 << id))
- raiseInterrupt();
+void
+PMU::CounterState::setValue(uint64_t val)
+{
+ value = val;
+ resetValue = true;
+
+ if (sourceEvent) {
+ sourceEvent->updateAttachedCounters();
+ } else {
+ debugCounter("attempted to set value from a counter without"
+ " an associated event\n");
}
}
void
-PMU::updateCounter(CounterId id, CounterState &ctr)
+PMU::updateCounter(CounterState &ctr)
{
if (!ctr.enabled) {
- if (!ctr.listeners.empty()) {
- DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id);
- ctr.listeners.clear();
- }
+ DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n",
+ ctr.getCounterId());
+ ctr.detach();
+
} else {
DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
- id, ctr.eventId);
-
- // Attach all probes belonging to this event
- auto range(pmuEventTypes.equal_range(ctr.eventId));
- for (auto it = range.first; it != range.second; ++it) {
- const EventType &et(it->second);
+ ctr.getCounterId(), ctr.eventId);
- DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name);
- ctr.listeners.emplace_back(et.create(*this, id));
- }
-
- /* The SW_INCR event type is a special case which doesn't need
- * any probes since it is controlled by software and the PMU
- * itself.
- */
- if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) {
+ auto sourceEvent = eventMap.find(ctr.eventId);
+ if (sourceEvent == eventMap.end()) {
warn("Can't enable PMU counter of type '0x%x': "
"No such event type.\n", ctr.eventId);
+ } else {
+ ctr.attach(sourceEvent->second);
}
}
}
@@ -459,7 +581,7 @@ void
PMU::resetEventCounts()
{
for (CounterState &ctr : counters)
- ctr.value = 0;
+ ctr.setValue(0);
}
void
@@ -472,7 +594,7 @@ PMU::setCounterValue(CounterId id, uint64_t val)
}
CounterState &ctr(getCounter(id));
- ctr.value = val;
+ ctr.setValue(val);
}
PMU::PMEVTYPER_t
@@ -509,7 +631,7 @@ PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
// need to update the probes the counter is using.
if (id != PMCCNTR && old_event_id != val.evtCount) {
ctr.eventId = val.evtCount;
- updateCounter(reg_pmselr.sel, ctr);
+ updateCounter(ctr);
}
}
@@ -574,6 +696,19 @@ PMU::unserialize(CheckpointIn &cp)
cycleCounter.unserializeSection(cp, "cycleCounter");
}
+PMU::PMUEvent*
+PMU::getEvent(uint64_t eventId)
+{
+ auto entry = eventMap.find(eventId);
+
+ if (entry == eventMap.end()) {
+ warn("event %d does not exist\n", eventId);
+ return nullptr;
+ } else {
+ return entry->second;
+ }
+}
+
void
PMU::CounterState::serialize(CheckpointOut &cp) const
{
@@ -590,16 +725,50 @@ PMU::CounterState::unserialize(CheckpointIn &cp)
UNSERIALIZE_SCALAR(overflow64);
}
-bool
+uint64_t
PMU::CounterState::add(uint64_t delta)
{
- const uint64_t msb(1ULL << (overflow64 ? 63 : 31));
- const uint64_t old_value(value);
+ uint64_t value_until_overflow;
+ if (overflow64) {
+ value_until_overflow = UINT64_MAX - value;
+ } else {
+ value_until_overflow = UINT32_MAX - (uint32_t)value;
+ }
+
+ if (isFiltered())
+ return value_until_overflow;
+
+ if (resetValue) {
+ delta = 0;
+ resetValue = false;
+ } else {
+ value += delta;
+ }
- value += delta;
+ if (delta > value_until_overflow) {
- // Overflow if the msb goes from 1 to 0
- return (old_value & msb) && !(value & msb);
+ // overflow situation detected
+ // flag the overflow occurence
+ pmu.reg_pmovsr |= (1 << counterId);
+
+ // Deliver a PMU interrupt if interrupt delivery is enabled
+ // for this counter.
+ if (pmu.reg_pminten & (1 << counterId)) {
+ pmu.raiseInterrupt();
+ }
+ return overflow64 ? UINT64_MAX : UINT32_MAX;
+ }
+ return value_until_overflow - delta + 1;
+}
+
+void
+PMU::SWIncrementEvent::write(uint64_t val)
+{
+ for (auto& counter: userCounters) {
+ if (val & (0x1 << counter->getCounterId())) {
+ counter->add(1);
+ }
+ }
}
} // namespace ArmISA
diff --git a/src/arch/arm/pmu.hh b/src/arch/arm/pmu.hh
index aecdfd84e..7090b4a78 100644
--- a/src/arch/arm/pmu.hh
+++ b/src/arch/arm/pmu.hh
@@ -47,8 +47,13 @@
#include "arch/arm/isa_device.hh"
#include "arch/arm/registers.hh"
-#include "sim/probe/probe.hh"
+#include "arch/arm/system.hh"
+#include "base/cprintf.hh"
+#include "cpu/base.hh"
+#include "debug/PMUVerbose.hh"
+#include "sim/eventq.hh"
#include "sim/sim_object.hh"
+#include "sim/system.hh"
class ArmPMUParams;
class Platform;
@@ -94,6 +99,9 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
~PMU();
void addEventProbe(unsigned int id, SimObject *obj, const char *name);
+ void addSoftwareIncrementEvent(unsigned int id);
+
+ void registerEvent(uint32_t id);
public: // SimObject and related interfaces
void serialize(CheckpointOut &cp) const override;
@@ -101,6 +109,7 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
void drainResume() override;
+ void regProbeListeners() override;
public: // ISA Device interface
/**
@@ -183,9 +192,6 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
*/
typedef unsigned int EventTypeId;
- /** ID of the software increment event */
- static const EventTypeId ARCH_EVENT_SW_INCR = 0x00;
-
protected: /* High-level register and interrupt handling */
MiscReg readMiscRegInt(int misc_reg);
@@ -220,7 +226,7 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
* not exist.
*/
uint64_t getCounterValue(CounterId id) const {
- return isValidCounter(id) ? getCounter(id).value : 0;
+ return isValidCounter(id) ? getCounter(id).getValue() : 0;
}
/**
@@ -261,74 +267,135 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
void setCounterTypeRegister(CounterId id, PMEVTYPER_t type);
protected: /* Probe handling and counter state */
- class ProbeListener : public ProbeListenerArgBase<uint64_t>
- {
- public:
- ProbeListener(PMU &_pmu, CounterId _id,
- ProbeManager *pm, const std::string &name)
- : ProbeListenerArgBase(pm, name),
- pmu(_pmu), id(_id) {}
-
- void notify(const uint64_t &val) override
- {
- pmu.handleEvent(id, val);
- }
-
- protected:
- PMU &pmu;
- const CounterId id;
- };
- typedef std::unique_ptr<ProbeListener> ProbeListenerUPtr;
+ struct CounterState;
/**
- * Event type configuration
- *
- * The main purpose of this class is to describe how a PMU event
- * type is sampled. It is implemented as a probe factory that
- * returns a probe attached to the object the event is mointoring.
+ * Event definition base class
*/
- struct EventType {
+ struct PMUEvent {
+
+ PMUEvent() {}
+
+ virtual ~PMUEvent() {}
+
/**
- * @param _obj Target SimObject
- * @param _name Probe name
+ * attach this event to a given counter
+ *
+ * @param a pointer to the counter where to attach this event
*/
- EventType(SimObject *_obj, const std::string &_name)
- : obj(_obj), name(_name) {}
+ void attachEvent(PMU::CounterState *user);
/**
- * Create and attach a probe used to drive this event.
+ * detach this event from a given counter
*
- * @param pmu PMU owning the probe.
- * @param CounterID counter ID within the PMU.
- * @return Pointer to a probe listener.
+ * @param a pointer to the counter where to detach this event from
*/
- std::unique_ptr<ProbeListener> create(PMU &pmu, CounterId cid) const
- {
- std::unique_ptr<ProbeListener> ptr;
- ptr.reset(new ProbeListener(pmu, cid,
- obj->getProbeManager(), name));
- return ptr;
- }
+ void detachEvent(PMU::CounterState *user);
+
+ /**
+ * notify an event increment of val units, all the attached counters'
+ * value is incremented by val units.
+ *
+ * @param the quantity by which to increment the attached counter
+ * values
+ */
+ virtual void increment(const uint64_t val);
+
+ /**
+ * Enable the current event
+ */
+ virtual void enable() = 0;
+
+ /**
+ * Disable the current event
+ */
+ virtual void disable() = 0;
- /** SimObject being measured by this probe */
- SimObject *const obj;
- /** Probe name within obj */
- const std::string name;
+ /**
+ * Method called immediately before a counter access in order for
+ * the associated event to update its state (if required)
+ */
+ virtual void updateAttachedCounters() {}
+
+ protected:
- private:
- // Disable the default constructor
- EventType();
+ /** set of counters using this event **/
+ std::set<PMU::CounterState*> userCounters;
};
- /** State of a counter within the PMU. */
- struct CounterState : public Serializable {
- CounterState()
- : eventId(0), filter(0), value(0), enabled(false),
- overflow64(false) {
+ struct RegularEvent : public PMUEvent {
+ typedef std::pair<SimObject*, std::string> EventTypeEntry;
+
+ void addMicroarchitectureProbe(SimObject* object,
+ std::string name) {
+
+ panic_if(!object,"malformed probe-point"
+ " definition with name %s\n", name);
- listeners.reserve(4);
+ microArchitectureEventSet.emplace(object, name);
}
+ protected:
+ struct RegularProbe: public ProbeListenerArgBase<uint64_t>
+ {
+ RegularProbe(RegularEvent *parent, SimObject* obj,
+ std::string name)
+ : ProbeListenerArgBase(obj->getProbeManager(), name),
+ parentEvent(parent) {}
+
+ RegularProbe() = delete;
+
+ void notify(const uint64_t &val);
+
+ protected:
+ RegularEvent *parentEvent;
+ };
+
+ /** The set of events driving the event value **/
+ std::set<EventTypeEntry> microArchitectureEventSet;
+
+ /** Set of probe listeners tapping onto each of the input micro-arch
+ * events which compose this pmu event
+ */
+ std::vector<std::unique_ptr<RegularProbe>> attachedProbePointList;
+
+ void enable() override;
+
+ void disable() override;
+ };
+
+ class SWIncrementEvent : public PMUEvent
+ {
+ void enable() override {}
+ void disable() override {}
+
+ public:
+
+ /**
+ * write on the sw increment register inducing an increment of the
+ * counters with this event selected according to the bitfield written.
+ *
+ * @param the bitfield selecting the counters to increment.
+ */
+ void write(uint64_t val);
+ };
+
+ /**
+ * Obtain the event of a given id
+ *
+ * @param the id of the event to obtain
+ * @return a pointer to the event with id eventId
+ */
+ PMUEvent* getEvent(uint64_t eventId);
+
+ /** State of a counter within the PMU. **/
+ struct CounterState : public Serializable {
+ CounterState(PMU &pmuReference, uint64_t counter_id)
+ : eventId(0), filter(0), enabled(false),
+ overflow64(false), sourceEvent(nullptr),
+ counterId(counter_id), value(0), resetValue(false),
+ pmu(pmuReference) {}
+
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
@@ -336,9 +403,46 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
* Add an event count to the counter and check for overflow.
*
* @param delta Number of events to add to the counter.
- * @return true on overflow, false otherwise.
+ * @return the quantity remaining until a counter overflow occurs.
+ */
+ uint64_t add(uint64_t delta);
+
+ bool isFiltered() const;
+
+ /**
+ * Detach the counter from its event
+ */
+ void detach();
+
+ /**
+ * Attach this counter to an event
+ *
+ * @param the event to attach the counter to
*/
- bool add(uint64_t delta);
+ void attach(PMUEvent* event);
+
+ /**
+ * Obtain the counter id
+ *
+ * @return the pysical counter id
+ */
+ uint64_t getCounterId() const{
+ return counterId;
+ }
+
+ /**
+ * rReturn the counter value
+ *
+ * @return the counter value
+ */
+ uint64_t getValue() const;
+
+ /**
+ * overwrite the value of the counter
+ *
+ * @param the new counter value
+ */
+ void setValue(uint64_t val);
public: /* Serializable state */
/** Counter event ID */
@@ -347,32 +451,37 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
/** Filtering settings (evtCount is unused) */
PMEVTYPER_t filter;
- /** Current value of the counter */
- uint64_t value;
-
/** Is the counter enabled? */
bool enabled;
/** Is this a 64-bit counter? */
bool overflow64;
- public: /* Configuration */
- /** Probe listeners driving this counter */
- std::vector<ProbeListenerUPtr> listeners;
- };
+ protected: /* Configuration */
+ /** PmuEvent currently in use (if any) **/
+ PMUEvent *sourceEvent;
- /**
- * Handle an counting event triggered by a probe.
- *
- * This method is called by the ProbeListener class whenever an
- * active probe is triggered. Ths method adds the event count from
- * the probe to the affected counter, checks for overflows, and
- * delivers an interrupt if needed.
- *
- * @param id Counter ID affected by the probe.
- * @param delta Counter increment
- */
- void handleEvent(CounterId id, uint64_t delta);
+ /** id of the counter instance **/
+ uint64_t counterId;
+
+ /** Current value of the counter */
+ uint64_t value;
+
+ /** Flag keeping track if the counter has been reset **/
+ bool resetValue;
+
+ PMU &pmu;
+
+ template <typename ...Args>
+ void debugCounter(const char* mainString, Args &...args) const {
+
+ std::string userString = csprintf(mainString, args...);
+
+ warn("[counterId = %d, eventId = %d, sourceEvent = 0x%x] %s",
+ counterId, eventId, sourceEvent, userString.c_str());
+
+ }
+ };
/**
* Is this a valid counter ID?
@@ -398,7 +507,6 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
return id == PMCCNTR ? cycleCounter : counters[id];
}
-
/**
* Return the state of a counter.
*
@@ -422,7 +530,7 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
* @param id ID of counter within the PMU.
* @param ctr Reference to the counter's state
*/
- void updateCounter(CounterId id, CounterState &ctr);
+ void updateCounter(CounterState &ctr);
/**
* Check if a counter's settings allow it to be counted.
@@ -468,14 +576,25 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
/** Remainder part when the clock counter is divided by 64 */
unsigned clock_remainder;
+ /** The number of regular event counters **/
+ uint64_t maximumCounterCount;
+
/** State of all general-purpose counters supported by PMU */
std::vector<CounterState> counters;
+
/** State of the cycle counter */
CounterState cycleCounter;
+ /** The id of the counter hardwired to the cpu cycle counter **/
+ const uint64_t cycleCounterEventId;
+
+ /** The event that implements the software increment **/
+ SWIncrementEvent *swIncrementEvent;
+
protected: /* Configuration and constants */
/** Constant (configuration-dependent) part of the PMCR */
PMCR_t reg_pmcr_conf;
+
/** PMCR write mask when accessed from the guest */
static const MiscReg reg_pmcr_wr_mask;
@@ -485,22 +604,9 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
Platform *const platform;
/**
- * Event types supported by this PMU.
- *
- * Each event type ID can map to multiple EventType structures,
- * which enables the PMU to use multiple probes for a single
- * event. This can be useful in the following cases:
- * <ul>
- * <li>Some events can are increment by multiple different probe
- * points (e.g., the CPU memory access counter gets
- * incremented for both loads and stores).
- *
- * <li>A system switching between multiple CPU models can
- * register events for all models that will execute a thread
- * and tehreby ensure that the PMU continues to work.
- * </ul>
+ * List of event types supported by this PMU.
*/
- std::multimap<EventTypeId, EventType> pmuEventTypes;
+ std::map<EventTypeId, PMUEvent*> eventMap;
};
} // namespace ArmISA