} 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();
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();
DRAMCtrl::Rank::suspend()
{
deschedule(refreshEvent);
+
+ // Update the stats
+ updatePowerStats();
}
void
// 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();
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();
{
// 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());
}
}
+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()
{
*/
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.
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);