cpu: Probe points for basic PMU stats
authorAndreas Sandberg <Andreas.Sandberg@ARM.com>
Thu, 16 Oct 2014 09:49:41 +0000 (05:49 -0400)
committerAndreas Sandberg <Andreas.Sandberg@ARM.com>
Thu, 16 Oct 2014 09:49:41 +0000 (05:49 -0400)
This changeset adds probe points that can be used to implement PMU
counters for CPU stats. The following probes are supported:

  * BaseCPU::ppCycles / Cycles
  * BaseCPU::ppRetiredInsts / RetiredInsts
  * BaseCPU::ppRetiredLoads / RetiredLoads
  * BaseCPU::ppRetiredStores / RetiredStores
  * BaseCPU::ppRetiredBranches RetiredBranches

src/cpu/base.cc
src/cpu/base.hh
src/cpu/minor/execute.cc
src/cpu/minor/pipeline.hh
src/cpu/o3/cpu.cc
src/cpu/simple/atomic.cc
src/cpu/simple/base.cc
src/cpu/simple/timing.cc
src/cpu/simple/timing.hh
src/sim/ticked_object.hh

index c8c8ac57171c3e77ab9169cc41073912121cf864..ea4df2aa8e8120442fa7fe400d7663a421862f7d 100644 (file)
@@ -283,6 +283,42 @@ BaseCPU::startup()
     }
 }
 
+ProbePoints::PMUUPtr
+BaseCPU::pmuProbePoint(const char *name)
+{
+    ProbePoints::PMUUPtr ptr;
+    ptr.reset(new ProbePoints::PMU(getProbeManager(), name));
+
+    return ptr;
+}
+
+void
+BaseCPU::regProbePoints()
+{
+    ppCycles = pmuProbePoint("Cycles");
+
+    ppRetiredInsts = pmuProbePoint("RetiredInsts");
+    ppRetiredLoads = pmuProbePoint("RetiredLoads");
+    ppRetiredStores = pmuProbePoint("RetiredStores");
+    ppRetiredBranches = pmuProbePoint("RetiredBranches");
+}
+
+void
+BaseCPU::probeInstCommit(const StaticInstPtr &inst)
+{
+    if (!inst->isMicroop() || inst->isLastMicroop())
+        ppRetiredInsts->notify(1);
+
+
+    if (inst->isLoad())
+        ppRetiredLoads->notify(1);
+
+    if (inst->isStore())
+        ppRetiredLoads->notify(1);
+
+    if (inst->isControl())
+        ppRetiredBranches->notify(1);
+}
 
 void
 BaseCPU::regStats()
index a124b4282b47638e53de1c340d89ad6bfdb94724..75c8f72630d11cedc2e2272729cc7a5f8ca67434 100644 (file)
@@ -62,6 +62,7 @@
 #include "sim/eventq.hh"
 #include "sim/full_system.hh"
 #include "sim/insttracer.hh"
+#include "sim/probe/pmu.hh"
 #include "sim/system.hh"
 
 struct BaseCPUParams;
@@ -280,6 +281,8 @@ class BaseCPU : public MemObject
     virtual void startup();
     virtual void regStats();
 
+    void regProbePoints() M5_ATTR_OVERRIDE;
+
     void registerThreadContexts();
 
     /**
@@ -437,6 +440,54 @@ class BaseCPU : public MemObject
      */
     void scheduleLoadStop(ThreadID tid, Counter loads, const char *cause);
 
+  public:
+    /**
+     * @{
+     * @name PMU Probe points.
+     */
+
+    /**
+     * Helper method to trigger PMU probes for a committed
+     * instruction.
+     *
+     * @param inst Instruction that just committed
+     */
+    virtual void probeInstCommit(const StaticInstPtr &inst);
+
+    /**
+     * Helper method to instantiate probe points belonging to this
+     * object.
+     *
+     * @param name Name of the probe point.
+     * @return A unique_ptr to the new probe point.
+     */
+    ProbePoints::PMUUPtr pmuProbePoint(const char *name);
+
+    /** CPU cycle counter */
+    ProbePoints::PMUUPtr ppCycles;
+
+    /**
+     * Instruction commit probe point.
+     *
+     * This probe point is triggered whenever one or more instructions
+     * are committed. It is normally triggered once for every
+     * instruction. However, CPU models committing bundles of
+     * instructions may call notify once for the entire bundle.
+     */
+    ProbePoints::PMUUPtr ppRetiredInsts;
+
+    /** Retired load instructions */
+    ProbePoints::PMUUPtr ppRetiredLoads;
+    /** Retired store instructions */
+    ProbePoints::PMUUPtr ppRetiredStores;
+
+    /** Retired branches (any type) */
+    ProbePoints::PMUUPtr ppRetiredBranches;
+
+    /** @} */
+
+
+
     // Function tracing
   private:
     bool functionTracingEnabled;
index 5679f55a7f0f36596f1bdd66af912bb6e3edfd9c..5f840a273a83b523aacf05aa3261324a2c88636b 100644 (file)
@@ -853,6 +853,8 @@ Execute::doInstCommitAccounting(MinorDynInstPtr inst)
     /* Set the CP SeqNum to the numOps commit number */
     if (inst->traceData)
         inst->traceData->setCPSeq(thread->numOp);
+
+    cpu.probeInstCommit(inst->staticInst);
 }
 
 bool
index 893efbf509ccd36bb092eac498fee156477dabe7..355a3c6c2bea35d8efb41f530b757a505642e3c2 100644 (file)
@@ -126,6 +126,11 @@ class Pipeline : public Ticked
      *  stages and pipeline advance) */
     void evaluate();
 
+    void countCycles(Cycles delta) M5_ATTR_OVERRIDE
+    {
+        cpu.ppCycles->notify(delta);
+    }
+
     void minorTrace() const;
 
     /** Functions below here are BaseCPU operations passed on to pipeline
index 925b3d2d8e56279123ce4b14197dcc760f163ff6..6895355f07051a441d38f274b435c20e6910fdb1 100644 (file)
@@ -405,8 +405,11 @@ template <class Impl>
 void
 FullO3CPU<Impl>::regProbePoints()
 {
+    BaseCPU::regProbePoints();
+
     ppInstAccessComplete = new ProbePointArg<PacketPtr>(getProbeManager(), "InstAccessComplete");
     ppDataAccessComplete = new ProbePointArg<std::pair<DynInstPtr, PacketPtr> >(getProbeManager(), "DataAccessComplete");
+
     fetch.regProbePoints();
     iew.regProbePoints();
     commit.regProbePoints();
@@ -534,6 +537,7 @@ FullO3CPU<Impl>::tick()
     assert(getDrainState() != Drainable::Drained);
 
     ++numCycles;
+    ppCycles->notify(1);
 
 //    activity = false;
 
@@ -1444,6 +1448,8 @@ FullO3CPU<Impl>::instDone(ThreadID tid, DynInstPtr &inst)
     // Check for instruction-count-based events.
     comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst);
     system->instEventQueue.serviceEvents(system->totalNumInsts);
+
+    probeInstCommit(inst->staticInst);
 }
 
 template <class Impl>
@@ -1622,10 +1628,12 @@ FullO3CPU<Impl>::wakeCPU()
 
     Cycles cycles(curCycle() - lastRunningCycle);
     // @todo: This is an oddity that is only here to match the stats
-    if (cycles != 0)
+    if (cycles > 1) {
         --cycles;
-    idleCycles += cycles;
-    numCycles += cycles;
+        idleCycles += cycles;
+        numCycles += cycles;
+        ppCycles->notify(cycles);
+    }
 
     schedule(tickEvent, clockEdge());
 }
index 5af3854e7c1fff2b8f3c5bfb883d9e784bd0e78b..d6dbb92921a2bf2961f978b0dd7a196a510ebdf3 100644 (file)
@@ -233,7 +233,9 @@ AtomicSimpleCPU::activateContext(ThreadID thread_num)
     assert(!tickEvent.scheduled());
 
     notIdleFraction = 1;
-    numCycles += ticksToCycles(thread->lastActivate - thread->lastSuspend);
+    Cycles delta = ticksToCycles(thread->lastActivate - thread->lastSuspend);
+    numCycles += delta;
+    ppCycles->notify(delta);
 
     //Make sure ticks are still on multiples of cycles
     schedule(tickEvent, clockEdge(Cycles(0)));
@@ -501,6 +503,7 @@ AtomicSimpleCPU::tick()
 
     for (int i = 0; i < width || locked; ++i) {
         numCycles++;
+        ppCycles->notify(1);
 
         if (!curStaticInst || !curStaticInst->isDelayedCommit())
             checkForInterrupts();
@@ -614,6 +617,8 @@ AtomicSimpleCPU::tick()
 void
 AtomicSimpleCPU::regProbePoints()
 {
+    BaseCPU::regProbePoints();
+
     ppCommit = new ProbePointArg<pair<SimpleThread*, const StaticInstPtr>>
                                 (getProbeManager(), "Commit");
 }
index 6101ff30f6a570ee7a8b8a570993f9d975d98d19..60ab5399967f0cdf0e71e48714cf1edf45b7ea52 100644 (file)
@@ -544,6 +544,9 @@ BaseSimpleCPU::postExecute()
         delete traceData;
         traceData = NULL;
     }
+
+    // Call CPU instruction commit probes
+    probeInstCommit(curStaticInst);
 }
 
 void
index 9a9714bee341c96600f868608f028357f1f0e016..84a2c09fd1e558cd671fd3ad8f5ffb24c5f3c6d9 100644 (file)
@@ -178,7 +178,7 @@ TimingSimpleCPU::switchOut()
     assert(!stayAtPC);
     assert(microPC() == 0);
 
-    numCycles += curCycle() - previousCycle;
+    updateCycleCounts();
 }
 
 
@@ -332,8 +332,7 @@ TimingSimpleCPU::translationFault(const Fault &fault)
 {
     // fault may be NoFault in cases where a fault is suppressed,
     // for instance prefetches.
-    numCycles += curCycle() - previousCycle;
-    previousCycle = curCycle();
+    updateCycleCounts();
 
     if (traceData) {
         // Since there was a fault, we shouldn't trace this instruction.
@@ -569,8 +568,7 @@ TimingSimpleCPU::fetch()
         _status = IcacheWaitResponse;
         completeIfetch(NULL);
 
-        numCycles += curCycle() - previousCycle;
-        previousCycle = curCycle();
+        updateCycleCounts();
     }
 }
 
@@ -603,8 +601,7 @@ TimingSimpleCPU::sendFetch(const Fault &fault, RequestPtr req,
         advanceInst(fault);
     }
 
-    numCycles += curCycle() - previousCycle;
-    previousCycle = curCycle();
+    updateCycleCounts();
 }
 
 
@@ -651,8 +648,7 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
 
     _status = BaseSimpleCPU::Running;
 
-    numCycles += curCycle() - previousCycle;
-    previousCycle = curCycle();
+    updateCycleCounts();
 
     if (pkt)
         pkt->req->setAccessLatency();
@@ -753,8 +749,8 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
            pkt->req->getFlags().isSet(Request::NO_ACCESS));
 
     pkt->req->setAccessLatency();
-    numCycles += curCycle() - previousCycle;
-    previousCycle = curCycle();
+
+    updateCycleCounts();
 
     if (pkt->senderState) {
         SplitFragmentSenderState * send_state =
@@ -808,6 +804,17 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
     advanceInst(fault);
 }
 
+void
+TimingSimpleCPU::updateCycleCounts()
+{
+    const Cycles delta(curCycle() - previousCycle);
+
+    numCycles += delta;
+    ppCycles->notify(delta);
+
+    previousCycle = curCycle();
+}
+
 void
 TimingSimpleCPU::DcachePort::recvTimingSnoopReq(PacketPtr pkt)
 {
index 24f7002fff9bdfe9e241a65f0b8c841084f0629f..84c8f7418c15c8e5358aece72fee46140dfaff37 100644 (file)
@@ -245,13 +245,15 @@ class TimingSimpleCPU : public BaseSimpleCPU
 
     };
 
+    void updateCycleCounts();
+
     IcachePort icachePort;
     DcachePort dcachePort;
 
     PacketPtr ifetch_pkt;
     PacketPtr dcache_pkt;
 
-    Tick previousCycle;
+    Cycles previousCycle;
 
   protected:
 
index 5bca9244379c92c062a15763bda731aabeb74296..ee143e0df07b1e33ed81c6f46e98f12db5b39acb 100644 (file)
@@ -76,6 +76,7 @@ class Ticked
         {
             ++owner.tickCycles;
             ++owner.numCycles;
+            owner.countCycles(Cycles(1));
             owner.evaluate();
             if (owner.running) {
                 owner.object.schedule(this,
@@ -132,6 +133,7 @@ class Ticked
                 object.schedule(event, object.clockEdge(Cycles(1)));
             running = true;
             numCycles += cyclesSinceLastStopped();
+            countCycles(cyclesSinceLastStopped());
         }
     }
 
@@ -167,6 +169,19 @@ class Ticked
 
     /** Action to call on the clock tick */
     virtual void evaluate() = 0;
+
+    /**
+     * Callback to handle cycle statistics and probes.
+     *
+     * This callback is called at the beginning of a new cycle active
+     * cycle and when restarting the ticked object. The delta
+     * parameter indicates the number of cycles elapsed since the
+     * previous call is normally '1' unless the object has been
+     * stopped and restarted.
+     *
+     * @param delta Number of cycles since the previous call.
+     */
+    virtual void countCycles(Cycles delta) {}
 };
 
 /** TickedObject attaches Ticked to ClockedObject and can be used as