Andreas Sandberg has submitted this change and it was merged. ( https://gem5-review.googlesource.com/5764 )

Change subject: arch-arm: ArmPMU refactor
......................................................................

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.mari...@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandb...@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/5764
Maintainer: Andreas Sandberg <andreas.sandb...@arm.com>
---
M src/arch/arm/ArmPMU.py
M src/arch/arm/pmu.cc
M src/arch/arm/pmu.hh
3 files changed, 506 insertions(+), 204 deletions(-)

Approvals:
  Andreas Sandberg: Looks good to me, approved; Looks good to me, approved



diff --git a/src/arch/arm/ArmPMU.py b/src/arch/arm/ArmPMU.py
index 83c7dd4..a87c20b 100644
--- a/src/arch/arm/ArmPMU.py
+++ b/src/arch/arm/ArmPMU.py
@@ -43,38 +43,61 @@
 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 @@
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 @@
         # 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 baf0d19..0bdae49 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 @@
       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 @@
 }

 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 @@
 }

 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 @@

       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 @@
         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 @@
       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 @@

     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 @@
         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);
     }
 }

-bool
-PMU::isFiltered(const CounterState &ctr) const
+void
+PMU::PMUEvent::attachEvent(PMU::CounterState *user)
 {
-    assert(isa);
+    if (userCounters.empty()) {
+        enable();
+    }
+    userCounters.insert(user);
+    updateAttachedCounters();
+}

-    const PMEVTYPER_t filter(ctr.filter);
-    const SCR scr(isa->readMiscRegNoEffect(MISCREG_SCR));
-    const CPSR cpsr(isa->readMiscRegNoEffect(MISCREG_CPSR));
+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::CounterState::isFiltered() const
+{
+    assert(pmu.isa);
+
+    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 @@
 }

 void
-PMU::handleEvent(CounterId id, uint64_t delta)
+PMU::CounterState::detach()
 {
-    CounterState &ctr(getCounter(id));
-    const bool overflowed(reg_pmovsr & (1 << id));
-
-    if (isFiltered(ctr))
-        return;
-
-    // Handle the "count every 64 cycles" mode
-    if (id == PMCCNTR && reg_pmcr.d) {
-        clock_remainder += delta;
-        delta = (clock_remainder >> 6);
-        clock_remainder &= 63;
-    }
-
-    // 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();
+    if (sourceEvent) {
+        sourceEvent->detachEvent(this);
+        sourceEvent = nullptr;
+    } else {
+        debugCounter("detaching event not currently attached"
+            " to any event\n");
     }
 }

 void
-PMU::updateCounter(CounterId id, CounterState &ctr)
+PMU::CounterState::attach(PMUEvent* event)
+{
+    value = 0;
+    sourceEvent = event;
+    sourceEvent->attachEvent(this);
+}
+
+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;
+}
+
+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(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);
+                ctr.getCounterId(), 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);
-
- 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 @@
 PMU::resetEventCounts()
 {
     for (CounterState &ctr : counters)
-        ctr.value = 0;
+        ctr.setValue(0);
 }

 void
@@ -472,7 +594,7 @@
     }

     CounterState &ctr(getCounter(id));
-    ctr.value = val;
+    ctr.setValue(val);
 }

 PMU::PMEVTYPER_t
@@ -509,7 +631,7 @@
     // 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 @@
     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 @@
     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;
+    }

-    value += delta;
+    if (isFiltered())
+        return value_until_overflow;

-    // Overflow if the msb goes from 1 to 0
-    return (old_value & msb) && !(value & msb);
+    if (resetValue) {
+        delta = 0;
+        resetValue = false;
+    } else {
+        value += delta;
+    }
+
+    if (delta > value_until_overflow) {
+
+        // 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 aecdfd8..7090b4a 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 @@
     ~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 @@

     void drainResume() override;

+    void regProbeListeners() override;

   public: // ISA Device interface
     /**
@@ -183,9 +192,6 @@
      */
     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 @@
      * not exist.
      */
     uint64_t getCounterValue(CounterId id) const {
-        return isValidCounter(id) ? getCounter(id).value : 0;
+        return isValidCounter(id) ? getCounter(id).getValue() : 0;
     }

     /**
@@ -261,73 +267,134 @@
     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) {}
+    struct CounterState;

-        void notify(const uint64_t &val) override
-        {
-            pmu.handleEvent(id, val);
+    /**
+     * Event definition base class
+     */
+    struct PMUEvent {
+
+        PMUEvent() {}
+
+        virtual ~PMUEvent() {}
+
+        /**
+         * attach this event to a given counter
+         *
+         * @param a pointer to the counter where to attach this event
+         */
+        void attachEvent(PMU::CounterState *user);
+
+        /**
+         * detach this event from a given counter
+         *
+         * @param a pointer to the counter where to detach this event from
+         */
+        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;
+
+        /**
+         *  Method called immediately before a counter access in order for
+         *  the associated event to update its state (if required)
+         */
+        virtual void updateAttachedCounters() {}
+
+      protected:
+
+        /** set of counters using this event  **/
+        std::set<PMU::CounterState*> userCounters;
+    };
+
+    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);
+
+            microArchitectureEventSet.emplace(object, name);
         }

       protected:
-        PMU &pmu;
-        const CounterId id;
+        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;
     };
-    typedef std::unique_ptr<ProbeListener> ProbeListenerUPtr;
+
+    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);
+    };

     /**
-     * Event type configuration
+     * Obtain the event of a given id
      *
-     * 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.
+     * @param the id of the event to obtain
+     * @return a pointer to the event with id eventId
      */
-    struct EventType {
-        /**
-         * @param _obj Target SimObject
-         * @param _name Probe name
-         */
-        EventType(SimObject *_obj, const std::string &_name)
-            : obj(_obj), name(_name) {}
+    PMUEvent* getEvent(uint64_t eventId);

-        /**
-         * Create and attach a probe used to drive this event.
-         *
-         * @param pmu PMU owning the probe.
-         * @param CounterID counter ID within the PMU.
-         * @return Pointer to a probe listener.
-         */
- 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;
-        }
-
-        /** SimObject being measured by this probe */
-        SimObject *const obj;
-        /** Probe name within obj */
-        const std::string name;
-
-      private:
-        // Disable the default constructor
-        EventType();
-    };
-
-    /** State of a counter within the PMU. */
+    /** State of a counter within the PMU. **/
     struct CounterState : public Serializable {
-        CounterState()
-            : eventId(0), filter(0), value(0), enabled(false),
-              overflow64(false) {
-
-            listeners.reserve(4);
-        }
+        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 @@
          * 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.
          */
-        bool add(uint64_t delta);
+        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
+         */
+        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 @@
         /** 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 @@
         return id == PMCCNTR ? cycleCounter : counters[id];
     }

-
     /**
      * Return the state of a counter.
      *
@@ -422,7 +530,7 @@
      * @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 @@
     /** 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 @@
     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

--
To view, visit https://gem5-review.googlesource.com/5764
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: I43874b9641bf38c54f6ba2c26386542b6a73e282
Gerrit-Change-Number: 5764
Gerrit-PatchSet: 4
Gerrit-Owner: Andreas Sandberg <andreas.sandb...@arm.com>
Gerrit-Reviewer: Andreas Sandberg <andreas.sandb...@arm.com>
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to