mem: Modify drain to ensure banks and power are idled
authorWendy Elsasser <wendy.elsasser@arm.com>
Thu, 13 Oct 2016 18:22:11 +0000 (19:22 +0100)
committerWendy Elsasser <wendy.elsasser@arm.com>
Thu, 13 Oct 2016 18:22:11 +0000 (19:22 +0100)
Add constraint that all ranks have to be in PWR_IDLE
before signaling drain complete

This will ensure that the banks are all closed and the rank
has exited any low-power states.

On suspend, update the power stats to sync the DRAM power logic

The logic maintains the location of the signalDrainDone
method, which is still triggered from either:
1) Read response event
2) Next request event

This ensures that the drain will complete in the READ bus
state and minimizes the changes required.

Change-Id: If1476e631ea7d5999fe50a0c9379c5967a90e3d1
Reviewed-by: Radhika Jagtap <radhika.jagtap@arm.com>
src/mem/dram_ctrl.cc
src/mem/dram_ctrl.hh

index 51131a6a7cf07a668bfd5e291ffbe01572c94742..e13c2af02aecfce0b3802f1a200be82c1bce44c4 100644 (file)
@@ -684,7 +684,7 @@ DRAMCtrl::processRespondEvent()
     } else {
         // if there is nothing left in any queue, signal a drain
         if (drainState() == DrainState::Draining &&
-            writeQueue.empty() && readQueue.empty()) {
+            writeQueue.empty() && readQueue.empty() && allRanksDrained()) {
 
             DPRINTF(Drain, "DRAM controller done draining\n");
             signalDrainDone();
@@ -1288,8 +1288,11 @@ DRAMCtrl::processNextReqEvent()
                 switch_to_writes = true;
             } else {
                 // check if we are drained
+                // not done draining until in PWR_IDLE state
+                // ensuring all banks are closed and
+                // have exited low power states
                 if (drainState() == DrainState::Draining &&
-                    respQueue.empty()) {
+                    respQueue.empty() && allRanksDrained()) {
 
                     DPRINTF(Drain, "DRAM controller done draining\n");
                     signalDrainDone();
@@ -1538,6 +1541,9 @@ void
 DRAMCtrl::Rank::suspend()
 {
     deschedule(refreshEvent);
+
+    // Update the stats
+    updatePowerStats();
 }
 
 void
@@ -1708,23 +1714,6 @@ DRAMCtrl::Rank::processRefreshEvent()
         // at the moment this affects all ranks
         cmdList.push_back(Command(MemCommand::REF, 0, curTick()));
 
-        // All commands up to refresh have completed
-        // flush cmdList to DRAMPower
-        flushCmdList();
-
-        // update the counters for DRAMPower, passing false to
-        // indicate that this is not the last command in the
-        // list. DRAMPower requires this information for the
-        // correct calculation of the background energy at the end
-        // of the simulation. Ideally we would want to call this
-        // function with true once at the end of the
-        // simulation. However, the discarded energy is extremly
-        // small and does not effect the final results.
-        power.powerlib.updateCounters(false);
-
-        // call the energy function
-        power.powerlib.calcEnergy();
-
         // Update the stats
         updatePowerStats();
 
@@ -1833,6 +1822,23 @@ DRAMCtrl::Rank::processPowerEvent()
 void
 DRAMCtrl::Rank::updatePowerStats()
 {
+    // All commands up to refresh have completed
+    // flush cmdList to DRAMPower
+    flushCmdList();
+
+    // update the counters for DRAMPower, passing false to
+    // indicate that this is not the last command in the
+    // list. DRAMPower requires this information for the
+    // correct calculation of the background energy at the end
+    // of the simulation. Ideally we would want to call this
+    // function with true once at the end of the
+    // simulation. However, the discarded energy is extremly
+    // small and does not effect the final results.
+    power.powerlib.updateCounters(false);
+
+    // call the energy function
+    power.powerlib.calcEnergy();
+
     // Get the energy and power from DRAMPower
     Data::MemoryPowerModel::Energy energy =
         power.powerlib.getEnergy();
@@ -2182,7 +2188,9 @@ DRAMCtrl::drain()
 {
     // if there is anything in any of our internal queues, keep track
     // of that as well
-    if (!(writeQueue.empty() && readQueue.empty() && respQueue.empty())) {
+    if (!(writeQueue.empty() && readQueue.empty() && respQueue.empty() &&
+          allRanksDrained())) {
+
         DPRINTF(Drain, "DRAM controller not drained, write: %d, read: %d,"
                 " resp: %d\n", writeQueue.size(), readQueue.size(),
                 respQueue.size());
@@ -2198,6 +2206,19 @@ DRAMCtrl::drain()
     }
 }
 
+bool
+DRAMCtrl::allRanksDrained() const
+{
+    // true until proven false
+    bool all_ranks_drained = true;
+    for (auto r : ranks) {
+        // then verify that the power state is IDLE
+        // ensuring all banks are closed and rank is not in a low power state
+        all_ranks_drained = r->inPwrIdleState() && all_ranks_drained;
+    }
+    return all_ranks_drained;
+}
+
 void
 DRAMCtrl::drainResume()
 {
index 70b737652aad333b602964e8a3a18a46aaba2ba6..79a68af4b004e9aa4323a20013fe40db5d84f828 100644 (file)
@@ -381,6 +381,15 @@ class DRAMCtrl : public AbstractMemory
          */
         bool isAvailable() const { return refreshState == REF_IDLE; }
 
+        /**
+         * Check if the current rank has all banks closed and is not
+         * in a low power state
+         *
+         * @param Return true if the rank is idle from a bank
+         *        and power point of view
+         */
+        bool inPwrIdleState() const { return pwrState == PWR_IDLE; }
+
         /**
          * Let the rank check if it was waiting for requests to drain
          * to allow it to transition states.
@@ -913,6 +922,17 @@ class DRAMCtrl : public AbstractMemory
     virtual void startup() override;
     virtual void drainResume() override;
 
+    /**
+     * Return true once refresh is complete for all ranks and there are no
+     * additional commands enqueued.  (only evaluated when draining)
+     * This will ensure that all banks are closed, power state is IDLE, and
+     * power stats have been updated
+     *
+     * @return true if all ranks have refreshed, with no commands enqueued
+     *
+     */
+    bool allRanksDrained() const;
+
   protected:
 
     Tick recvAtomic(PacketPtr pkt);