sim-power: Fix the way the power model accesses stats
[gem5.git] / src / sim / clocked_object.hh
index e04e9338d560c98c9431224e6c906932670ec43d..10a7fedc74af56b0e865eadbaa59859470e15679 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2012-2013, 2015-2016 ARM Limited
+ * Copyright (c) 2013 Cornell University
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -33,8 +34,6 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Andreas Hansson
  */
 
 /**
 #ifndef __SIM_CLOCKED_OBJECT_HH__
 #define __SIM_CLOCKED_OBJECT_HH__
 
+#include "base/callback.hh"
 #include "base/intmath.hh"
-#include "base/misc.hh"
+#include "enums/PwrState.hh"
 #include "params/ClockedObject.hh"
 #include "sim/core.hh"
+#include "sim/clock_domain.hh"
 #include "sim/sim_object.hh"
 
 /**
- * The ClockedObject class extends the SimObject with a clock and
- * accessor functions to relate ticks to the cycles of the object.
+ * Helper class for objects that need to be clocked. Clocked objects
+ * typically inherit from this class. Objects that need SimObject
+ * functionality as well should inherit from ClockedObject.
  */
-class ClockedObject : public SimObject
+class Clocked
 {
 
   private:
-
     // the tick value of the next clock edge (>= curTick()) at the
     // time of the last call to update()
     mutable Tick tick;
@@ -69,16 +70,11 @@ class ClockedObject : public SimObject
     mutable Cycles cycle;
 
     /**
-     * Prevent inadvertent use of the copy constructor and assignment
-     * operator by making them private.
-     */
-    ClockedObject(ClockedObject&);
-    ClockedObject& operator=(ClockedObject&);
-
-    /**
-     *  Align cycle and tick to the next clock edge if not already done.
+     *  Align cycle and tick to the next clock edge if not already done. When
+     *  complete, tick must be at least curTick().
      */
-    void update() const
+    void
+    update() const
     {
         // both tick and cycle are up-to-date and we are done, note
         // that the >= is important as it captures cases where tick
@@ -88,7 +84,7 @@ class ClockedObject : public SimObject
 
         // optimise for the common case and see if the tick should be
         // advanced by a single clock period
-        tick += clock;
+        tick += clockPeriod();
         ++cycle;
 
         // see if we are done at this point
@@ -98,72 +94,103 @@ class ClockedObject : public SimObject
         // if not, we have to recalculate the cycle and tick, we
         // perform the calculations in terms of relative cycles to
         // allow changes to the clock period in the future
-        Cycles elapsedCycles(divCeil(curTick() - tick, clock));
+        Cycles elapsedCycles(divCeil(curTick() - tick, clockPeriod()));
         cycle += elapsedCycles;
-        tick += elapsedCycles * clock;
+        tick += elapsedCycles * clockPeriod();
     }
 
-    // Clock period in ticks
-    Tick clock;
+    /**
+     * The clock domain this clocked object belongs to
+     */
+    ClockDomain &clockDomain;
 
   protected:
 
     /**
-     * Create a clocked object and set the clock based on the
+     * Create a clocked object and set the clock domain based on the
      * parameters.
      */
-    ClockedObject(const ClockedObjectParams* p) :
-        SimObject(p), tick(0), cycle(0), clock(p->clock)
+    Clocked(ClockDomain &clk_domain)
+        : tick(0), cycle(0), clockDomain(clk_domain)
     {
-        if (clock == 0) {
-            fatal("%s has a clock period of zero\n", name());
-        }
+        // Register with the clock domain, so that if the clock domain
+        // frequency changes, we can update this object's tick.
+        clockDomain.registerWithClockDomain(this);
     }
 
+    Clocked(Clocked &) = delete;
+    Clocked &operator=(Clocked &) = delete;
+
     /**
      * Virtual destructor due to inheritance.
      */
-    virtual ~ClockedObject() { }
+    virtual ~Clocked() { }
 
     /**
      * Reset the object's clock using the current global tick value. Likely
      * to be used only when the global clock is reset. Currently, this done
      * only when Ruby is done warming up the memory system.
      */
-    void resetClock() const
+    void
+    resetClock() const
     {
-        Cycles elapsedCycles(divCeil(curTick(), clock));
+        Cycles elapsedCycles(divCeil(curTick(), clockPeriod()));
         cycle = elapsedCycles;
-        tick = elapsedCycles * clock;
+        tick = elapsedCycles * clockPeriod();
     }
 
+    /**
+     * A hook subclasses can implement so they can do any extra work that's
+     * needed when the clock rate is changed.
+     */
+    virtual void clockPeriodUpdated() {}
+
   public:
 
     /**
-     * Determine the tick when a cycle begins, by default the current
-     * one, but the argument also enables the caller to determine a
-     * future cycle.
+     * Update the tick to the current tick.
+     */
+    void
+    updateClockPeriod()
+    {
+        update();
+        clockPeriodUpdated();
+    }
+
+    /**
+     * Determine the tick when a cycle begins, by default the current one, but
+     * the argument also enables the caller to determine a future cycle. When
+     * curTick() is on a clock edge, the number of cycles in the parameter is
+     * added to curTick() to be returned. When curTick() is not aligned to a
+     * clock edge, the number of cycles in the parameter is added to the next
+     * clock edge.
      *
      * @param cycles The number of cycles into the future
      *
-     * @return The tick when the clock edge occurs
+     * @return The start tick when the requested clock edge occurs. Precisely,
+     * this tick can be
+     *     curTick() + [0, clockPeriod()) + clockPeriod() * cycles
      */
-    inline Tick clockEdge(Cycles cycles = Cycles(0)) const
+    Tick
+    clockEdge(Cycles cycles=Cycles(0)) const
     {
         // align tick to the next clock edge
         update();
 
         // figure out when this future cycle is
-        return tick + clock * cycles;
+        return tick + clockPeriod() * cycles;
     }
 
     /**
      * Determine the current cycle, corresponding to a tick aligned to
      * a clock edge.
      *
-     * @return The current cycle count
+     * @return When curTick() is on a clock edge, return the Cycle corresponding
+     * to that clock edge. When curTick() is not on a clock edge, return the
+     * Cycle corresponding to the next clock edge.
      */
-    inline Cycles curCycle() const
+    Cycles
+    curCycle() const
     {
         // align cycle to the next clock edge.
         update();
@@ -172,21 +199,92 @@ class ClockedObject : public SimObject
     }
 
     /**
-     * Based on the clock of the object, determine the tick when the
-     * next cycle begins, in other words, return the next clock edge.
+     * Based on the clock of the object, determine the start tick of the first
+     * cycle that is at least one cycle in the future. When curTick() is at the
+     * current cycle edge, this returns the next clock edge. When calling this
+     * during the middle of a cycle, this returns 2 clock edges in the future.
      *
-     * @return The tick when the next cycle starts
+     * @return The start tick of the first cycle that is at least one cycle in
+     * the future. Precisely, the returned tick can be in the range
+     *     curTick() + [clockPeriod(), 2 * clockPeriod())
      */
-    Tick nextCycle() const
-    { return clockEdge(); }
+    Tick nextCycle() const { return clockEdge(Cycles(1)); }
+
+    uint64_t frequency() const { return SimClock::Frequency / clockPeriod(); }
 
-    inline uint64_t frequency() const { return SimClock::Frequency / clock; }
+    Tick clockPeriod() const { return clockDomain.clockPeriod(); }
+
+    double voltage() const { return clockDomain.voltage(); }
+
+    Cycles
+    ticksToCycles(Tick t) const
+    {
+        return Cycles(divCeil(t, clockPeriod()));
+    }
+
+    Tick cyclesToTicks(Cycles c) const { return clockPeriod() * c; }
+};
 
-    inline Tick clockPeriod() const { return clock; }
+/**
+ * The ClockedObject class extends the SimObject with a clock and
+ * accessor functions to relate ticks to the cycles of the object.
+ */
+class ClockedObject : public SimObject, public Clocked
+{
+  public:
+    ClockedObject(const ClockedObjectParams *p);
+
+    /** Parameters of ClockedObject */
+    typedef ClockedObjectParams Params;
+    const Params *
+    params() const
+    {
+        return reinterpret_cast<const Params*>(_params);
+    }
+
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+
+    Enums::PwrState pwrState() const { return _currPwrState; }
+
+    std::string
+    pwrStateName() const
+    {
+        return Enums::PwrStateStrings[_currPwrState];
+    }
+
+    /** Returns the percentage residency for each power state */
+    std::vector<double> pwrStateWeights() const;
+
+    /**
+     * Record stats values like state residency by computing the time
+     * difference from previous update. Also, updates the previous evaluation
+     * tick once all stats are recorded.
+     * Usually called on power state change and stats dump callback.
+     */
+    void computeStats();
+
+    void pwrState(Enums::PwrState);
+
+  protected:
+
+    /** To keep track of the current power state */
+    Enums::PwrState _currPwrState;
+
+    Tick prvEvalTick;
+
+    struct ClockedObjectStats : public Stats::Group
+    {
+        ClockedObjectStats(ClockedObject &co);
 
-    inline Cycles ticksToCycles(Tick tick) const
-    { return Cycles(tick / clock); }
+        void regStats() override;
+        void preDumpStats() override;
 
+        ClockedObject &clockedObject;
+        Stats::Scalar numPwrStateTransitions;
+        Stats::Distribution pwrStateClkGateDist;
+        Stats::Vector pwrStateResidencyTicks;
+    } stats;
 };
 
 #endif //__SIM_CLOCKED_OBJECT_HH__