mem: Modify drain to ensure banks and power are idled

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>
This commit is contained in:
Wendy Elsasser 2016-10-13 19:22:11 +01:00
parent 27665af26d
commit 0dd0d4ee7a
2 changed files with 61 additions and 20 deletions

View file

@ -684,7 +684,7 @@ DRAMCtrl::processRespondEvent()
} else { } else {
// if there is nothing left in any queue, signal a drain // if there is nothing left in any queue, signal a drain
if (drainState() == DrainState::Draining && if (drainState() == DrainState::Draining &&
writeQueue.empty() && readQueue.empty()) { writeQueue.empty() && readQueue.empty() && allRanksDrained()) {
DPRINTF(Drain, "DRAM controller done draining\n"); DPRINTF(Drain, "DRAM controller done draining\n");
signalDrainDone(); signalDrainDone();
@ -1288,8 +1288,11 @@ DRAMCtrl::processNextReqEvent()
switch_to_writes = true; switch_to_writes = true;
} else { } else {
// check if we are drained // 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 && if (drainState() == DrainState::Draining &&
respQueue.empty()) { respQueue.empty() && allRanksDrained()) {
DPRINTF(Drain, "DRAM controller done draining\n"); DPRINTF(Drain, "DRAM controller done draining\n");
signalDrainDone(); signalDrainDone();
@ -1538,6 +1541,9 @@ void
DRAMCtrl::Rank::suspend() DRAMCtrl::Rank::suspend()
{ {
deschedule(refreshEvent); deschedule(refreshEvent);
// Update the stats
updatePowerStats();
} }
void void
@ -1708,23 +1714,6 @@ DRAMCtrl::Rank::processRefreshEvent()
// at the moment this affects all ranks // at the moment this affects all ranks
cmdList.push_back(Command(MemCommand::REF, 0, curTick())); 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 // Update the stats
updatePowerStats(); updatePowerStats();
@ -1833,6 +1822,23 @@ DRAMCtrl::Rank::processPowerEvent()
void void
DRAMCtrl::Rank::updatePowerStats() 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 // Get the energy and power from DRAMPower
Data::MemoryPowerModel::Energy energy = Data::MemoryPowerModel::Energy energy =
power.powerlib.getEnergy(); power.powerlib.getEnergy();
@ -2182,7 +2188,9 @@ DRAMCtrl::drain()
{ {
// if there is anything in any of our internal queues, keep track // if there is anything in any of our internal queues, keep track
// of that as well // 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," DPRINTF(Drain, "DRAM controller not drained, write: %d, read: %d,"
" resp: %d\n", writeQueue.size(), readQueue.size(), " resp: %d\n", writeQueue.size(), readQueue.size(),
respQueue.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 void
DRAMCtrl::drainResume() DRAMCtrl::drainResume()
{ {

View file

@ -381,6 +381,15 @@ class DRAMCtrl : public AbstractMemory
*/ */
bool isAvailable() const { return refreshState == REF_IDLE; } 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 * Let the rank check if it was waiting for requests to drain
* to allow it to transition states. * to allow it to transition states.
@ -913,6 +922,17 @@ class DRAMCtrl : public AbstractMemory
virtual void startup() override; virtual void startup() override;
virtual void drainResume() 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: protected:
Tick recvAtomic(PacketPtr pkt); Tick recvAtomic(PacketPtr pkt);