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.
This commit is contained in:
Andreas Hansson
2014-12-23 09:31:18 -05:00
parent 381d1da791
commit 2f7baf9dbe
2 changed files with 56 additions and 15 deletions

View File

@@ -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
@@ -1554,6 +1559,12 @@ DRAMCtrl::Rank::startup(Tick ref_tick)
schedule(refreshEvent, ref_tick);
}
void
DRAMCtrl::Rank::suspend()
{
deschedule(refreshEvent);
}
void
DRAMCtrl::Rank::checkDrainDone()
{
@@ -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)

View File

@@ -120,6 +120,11 @@ class DRAMCtrl : public AbstractMemory
*/
MemoryPort port;
/**
* Remeber if the memory system is in timing mode
*/
bool isTimingMode;
/**
* Remember if we have to retry a request when available.
*/
@@ -339,6 +344,11 @@ class DRAMCtrl : public AbstractMemory
*/
void startup(Tick ref_tick);
/**
* Stop the refresh events.
*/
void suspend();
/**
* Check if the current rank is available for scheduling.
*
@@ -855,8 +865,9 @@ class DRAMCtrl : public AbstractMemory
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: