From: Wendy Elsasser Date: Thu, 13 Oct 2016 18:22:11 +0000 (+0100) Subject: mem: Modify drain to ensure banks and power are idled X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0dd0d4ee7adb561e89a47c3e8284c237bebdc4ab;p=gem5.git 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 --- diff --git a/src/mem/dram_ctrl.cc b/src/mem/dram_ctrl.cc index 51131a6a7..e13c2af02 100644 --- a/src/mem/dram_ctrl.cc +++ b/src/mem/dram_ctrl.cc @@ -684,7 +684,7 @@ DRAMCtrl::processRespondEvent() } else { // if there is nothing left in any queue, signal a drain if (drainState() == DrainState::Draining && - writeQueue.empty() && readQueue.empty()) { + writeQueue.empty() && readQueue.empty() && allRanksDrained()) { DPRINTF(Drain, "DRAM controller done draining\n"); signalDrainDone(); @@ -1288,8 +1288,11 @@ DRAMCtrl::processNextReqEvent() switch_to_writes = true; } else { // 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 && - respQueue.empty()) { + respQueue.empty() && allRanksDrained()) { DPRINTF(Drain, "DRAM controller done draining\n"); signalDrainDone(); @@ -1538,6 +1541,9 @@ void DRAMCtrl::Rank::suspend() { deschedule(refreshEvent); + + // Update the stats + updatePowerStats(); } void @@ -1708,23 +1714,6 @@ DRAMCtrl::Rank::processRefreshEvent() // at the moment this affects all ranks 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 updatePowerStats(); @@ -1833,6 +1822,23 @@ DRAMCtrl::Rank::processPowerEvent() void 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 Data::MemoryPowerModel::Energy energy = power.powerlib.getEnergy(); @@ -2182,7 +2188,9 @@ DRAMCtrl::drain() { // if there is anything in any of our internal queues, keep track // 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," " resp: %d\n", writeQueue.size(), readQueue.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 DRAMCtrl::drainResume() { diff --git a/src/mem/dram_ctrl.hh b/src/mem/dram_ctrl.hh index 70b737652..79a68af4b 100644 --- a/src/mem/dram_ctrl.hh +++ b/src/mem/dram_ctrl.hh @@ -381,6 +381,15 @@ class DRAMCtrl : public AbstractMemory */ 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 * to allow it to transition states. @@ -913,6 +922,17 @@ class DRAMCtrl : public AbstractMemory virtual void startup() 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: Tick recvAtomic(PacketPtr pkt);