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:
parent
27665af26d
commit
0dd0d4ee7a
2 changed files with 61 additions and 20 deletions
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue