summaryrefslogtreecommitdiff
path: root/src/mem/dram_ctrl.cc
diff options
context:
space:
mode:
authorAndreas Hansson <andreas.hansson@arm.com>2014-12-23 09:31:18 -0500
committerAndreas Hansson <andreas.hansson@arm.com>2014-12-23 09:31:18 -0500
commit2f7baf9dbe7fd2cd716885adacf508a5b89e9eb8 (patch)
tree7e758a6d628f67c5407aba0d3d9bca142e3da5c7 /src/mem/dram_ctrl.cc
parent381d1da79147fbe8ae62ab4886446bdd7b3c478f (diff)
downloadgem5-2f7baf9dbe7fd2cd716885adacf508a5b89e9eb8.tar.xz
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 (limited to 'src/mem/dram_ctrl.cc')
-rw-r--r--src/mem/dram_ctrl.cc56
1 files changed, 43 insertions, 13 deletions
diff --git a/src/mem/dram_ctrl.cc b/src/mem/dram_ctrl.cc
index eec4706a6..42abc63a8 100644
--- a/src/mem/dram_ctrl.cc
+++ b/src/mem/dram_ctrl.cc
@@ -57,7 +57,7 @@ using namespace Data;
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 @@ DRAMCtrl::init()
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 @@ DRAMCtrl::Rank::startup(Tick ref_tick)
}
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 @@ DRAMCtrl::drain(DrainManager *dm)
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)