changeset 6dd27a0e0d23 in /z/repo/gem5
details: http://repo.gem5.org/gem5?cmd=changeset;node=6dd27a0e0d23
description:
        mem: Ensure DRAM controller is idle when in atomic mode

        This patch addresses an issue seen with the KVM CPU where the refresh
        events scheduled by the DRAM controller forces the simulator to switch
        out of the KVM mode, thus killing performance.

        The current patch works around the fact that we currently have no
        proper API to inform a SimObject of the mode switches. Instead we rely
        on drainResume being called after any switch, and cache the previous
        mode locally to be able to decide on appropriate actions.

        The switcheroo regression require a minor stats bump as a result.

diffstat:

 src/mem/dram_ctrl.cc |  56 +++++++++++++++++++++++++++++++++++++++------------
 src/mem/dram_ctrl.hh |  15 ++++++++++++-
 2 files changed, 56 insertions(+), 15 deletions(-)

diffs (128 lines):

diff -r bb665366cc00 -r 6dd27a0e0d23 src/mem/dram_ctrl.cc
--- a/src/mem/dram_ctrl.cc      Tue Dec 23 09:31:18 2014 -0500
+++ b/src/mem/dram_ctrl.cc      Tue Dec 23 09:31:18 2014 -0500
@@ -57,7 +57,7 @@
 
 DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) :
     AbstractMemory(p),
-    port(name() + ".port", *this),
+    port(name() + ".port", *this), isTimingMode(false),
     retryRdReq(false), retryWrReq(false),
     busState(READ),
     nextReqEvent(this), respondEvent(this),
@@ -239,20 +239,25 @@
 void
 DRAMCtrl::startup()
 {
-    // timestamp offset should be in clock cycles for DRAMPower
-    timeStampOffset = divCeil(curTick(), tCK);
+    // remember the memory system mode of operation
+    isTimingMode = system()->isTimingMode();
 
-    // update the start tick for the precharge accounting to the
-    // current tick
-    for (auto r : ranks) {
-        r->startup(curTick() + tREFI - tRP);
+    if (isTimingMode) {
+        // timestamp offset should be in clock cycles for DRAMPower
+        timeStampOffset = divCeil(curTick(), tCK);
+
+        // update the start tick for the precharge accounting to the
+        // current tick
+        for (auto r : ranks) {
+            r->startup(curTick() + tREFI - tRP);
+        }
+
+        // shift the bus busy time sufficiently far ahead that we never
+        // have to worry about negative values when computing the time for
+        // the next request, this will add an insignificant bubble at the
+        // start of simulation
+        busBusyUntil = curTick() + tRP + tRCD + tCL;
     }
-
-    // shift the bus busy time sufficiently far ahead that we never
-    // have to worry about negative values when computing the time for
-    // the next request, this will add an insignificant bubble at the
-    // start of simulation
-    busBusyUntil = curTick() + tRP + tRCD + tCL;
 }
 
 Tick
@@ -1555,6 +1560,12 @@
 }
 
 void
+DRAMCtrl::Rank::suspend()
+{
+    deschedule(refreshEvent);
+}
+
+void
 DRAMCtrl::Rank::checkDrainDone()
 {
     // if this rank was waiting to drain it is now able to proceed to
@@ -2197,6 +2208,25 @@
     return count;
 }
 
+void
+DRAMCtrl::drainResume()
+{
+    if (!isTimingMode && system()->isTimingMode()) {
+        // if we switched to timing mode, kick things into action,
+        // and behave as if we restored from a checkpoint
+        startup();
+    } else if (isTimingMode && !system()->isTimingMode()) {
+        // if we switch from timing mode, stop the refresh events to
+        // not cause issues with KVM
+        for (auto r : ranks) {
+            r->suspend();
+        }
+    }
+
+    // update the mode
+    isTimingMode = system()->isTimingMode();
+}
+
 DRAMCtrl::MemoryPort::MemoryPort(const std::string& name, DRAMCtrl& _memory)
     : QueuedSlavePort(name, &_memory, queue), queue(_memory, *this),
       memory(_memory)
diff -r bb665366cc00 -r 6dd27a0e0d23 src/mem/dram_ctrl.hh
--- a/src/mem/dram_ctrl.hh      Tue Dec 23 09:31:18 2014 -0500
+++ b/src/mem/dram_ctrl.hh      Tue Dec 23 09:31:18 2014 -0500
@@ -121,6 +121,11 @@
     MemoryPort port;
 
     /**
+     * Remeber if the memory system is in timing mode
+     */
+    bool isTimingMode;
+
+    /**
      * Remember if we have to retry a request when available.
      */
     bool retryRdReq;
@@ -340,6 +345,11 @@
         void startup(Tick ref_tick);
 
         /**
+         * Stop the refresh events.
+         */
+        void suspend();
+
+        /**
          * Check if the current rank is available for scheduling.
          *
          * @param Return true if the rank is idle from a refresh point of view
@@ -855,8 +865,9 @@
     virtual BaseSlavePort& getSlavePort(const std::string& if_name,
                                         PortID idx = InvalidPortID);
 
-    virtual void init();
-    virtual void startup();
+    virtual void init() M5_ATTR_OVERRIDE;
+    virtual void startup() M5_ATTR_OVERRIDE;
+    virtual void drainResume() M5_ATTR_OVERRIDE;
 
   protected:
 
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to