diff options
author | Radhika Jagtap <radhika.jagtap@arm.com> | 2016-12-19 10:32:40 +0000 |
---|---|---|
committer | Andreas Sandberg <andreas.sandberg@arm.com> | 2017-11-16 16:39:19 +0000 |
commit | 290a7e7c5c059c1309ca3d02ea3158e2ca9ac338 (patch) | |
tree | f04a5c7aa0f5247d467e1bb8b2139d0e11baf532 /src/mem | |
parent | 0757bef15d934b22555c396bcbcb91c0a1dffbe5 (diff) | |
download | gem5-290a7e7c5c059c1309ca3d02ea3158e2ca9ac338.tar.xz |
ext, mem: Pull DRAMPower SHA 90d6290 and rebase
This patch syncs the DRAMPower library of gem5 to the
external github (https://github.com/ravenrd/DRAMPower).
The version pulled in is the commit:
90d6290f802c29b3de9e10233ceee22290907ce6
from 30th Oct. 2016.
This change also modifies the DRAM Ctrl interaction with the
DRAMPower, due to changes in the lib API in the above version.
Previously multiple functions were called to prepare the power
lib before calling the function that would calculate the enery. With
the new API, these functions are encompassed inside the function to
calculate the energy and therefore should now be removed from the
DRAM controller.
The other key difference is the introduction of a new function called
calcWindowEnergy which can be useful for any system that wants
to do measurements over intervals. For gem5 DRAM ctrl that means we
now need to accumulate the window energy measurements into the total
stat.
Change-Id: I3570fff2805962e166ff2a1a3217ebf2d5a197fb
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/5724
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Diffstat (limited to 'src/mem')
-rw-r--r-- | src/mem/dram_ctrl.cc | 126 | ||||
-rw-r--r-- | src/mem/dram_ctrl.hh | 52 |
2 files changed, 114 insertions, 64 deletions
diff --git a/src/mem/dram_ctrl.cc b/src/mem/dram_ctrl.cc index da494a1d2..62de18de7 100644 --- a/src/mem/dram_ctrl.cc +++ b/src/mem/dram_ctrl.cc @@ -42,6 +42,7 @@ * Neha Agarwal * Omar Naji * Wendy Elsasser + * Radhika Jagtap */ #include "mem/dram_ctrl.hh" @@ -94,7 +95,8 @@ DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) : frontendLatency(p->static_frontend_latency), backendLatency(p->static_backend_latency), busBusyUntil(0), prevArrival(0), - nextReqTime(0), activeRank(0), timeStampOffset(0) + nextReqTime(0), activeRank(0), timeStampOffset(0), + lastStatsResetTick(0) { // sanity check the ranks since we rely on bit slicing for the // address decoding @@ -742,7 +744,7 @@ DRAMCtrl::chooseNext(std::deque<DRAMPacket*>& queue, Tick extra_col_delay) if (queue.size() == 1) { DRAMPacket* dram_pkt = queue.front(); // available rank corresponds to state refresh idle - if (ranks[dram_pkt->rank]->isAvailable()) { + if (ranks[dram_pkt->rank]->inRefIdleState()) { found_packet = true; DPRINTF(DRAM, "Single request, going to a free rank\n"); } else { @@ -755,7 +757,7 @@ DRAMCtrl::chooseNext(std::deque<DRAMPacket*>& queue, Tick extra_col_delay) // check if there is a packet going to a free rank for (auto i = queue.begin(); i != queue.end() ; ++i) { DRAMPacket* dram_pkt = *i; - if (ranks[dram_pkt->rank]->isAvailable()) { + if (ranks[dram_pkt->rank]->inRefIdleState()) { queue.erase(i); queue.push_front(dram_pkt); found_packet = true; @@ -801,8 +803,9 @@ DRAMCtrl::reorderQueue(std::deque<DRAMPacket*>& queue, Tick extra_col_delay) DRAMPacket* dram_pkt = *i; const Bank& bank = dram_pkt->bankRef; - // check if rank is available, if not, jump to the next packet - if (dram_pkt->rankRef.isAvailable()) { + // check if rank is not doing a refresh and thus is available, if not, + // jump to the next packet + if (dram_pkt->rankRef.inRefIdleState()) { // check if it is a row hit if (bank.openRow == dram_pkt->row) { // no additional rank-to-rank or same bank-group @@ -1268,7 +1271,7 @@ DRAMCtrl::processNextReqEvent() { int busyRanks = 0; for (auto r : ranks) { - if (!r->isAvailable()) { + if (!r->inRefIdleState()) { if (r->pwrState != PWR_SREF) { // rank is busy refreshing DPRINTF(DRAMState, "Rank %d is not available\n", r->rank); @@ -1385,7 +1388,7 @@ DRAMCtrl::processNextReqEvent() return; DRAMPacket* dram_pkt = readQueue.front(); - assert(dram_pkt->rankRef.isAvailable()); + assert(dram_pkt->rankRef.inRefIdleState()); // here we get a bit creative and shift the bus busy time not // just the tWTR, but also a CAS latency to capture the fact @@ -1442,15 +1445,16 @@ DRAMCtrl::processNextReqEvent() found_write = chooseNext(writeQueue, switched_cmd_type ? std::min(tRTW, tCS) : 0); - // if no writes to an available rank are found then return. - // There could be reads to the available ranks. However, to avoid - // adding more complexity to the code, return at this point and wait - // for a refresh event to kick things into action again. + // if there are no writes to a rank that is available to service + // requests (i.e. rank is in refresh idle state) are found then + // return. There could be reads to the available ranks. However, to + // avoid adding more complexity to the code, return at this point and + // wait for a refresh event to kick things into action again. if (!found_write) return; DRAMPacket* dram_pkt = writeQueue.front(); - assert(dram_pkt->rankRef.isAvailable()); + assert(dram_pkt->rankRef.inRefIdleState()); // sanity check assert(dram_pkt->size <= burstSize); @@ -1542,7 +1546,7 @@ DRAMCtrl::minBankPrep(const deque<DRAMPacket*>& queue, // bank in question vector<bool> got_waiting(ranksPerChannel * banksPerRank, false); for (const auto& p : queue) { - if (p->rankRef.isAvailable()) + if (p->rankRef.inRefIdleState()) got_waiting[p->bankId] = true; } @@ -1556,7 +1560,7 @@ DRAMCtrl::minBankPrep(const deque<DRAMPacket*>& queue, // amongst the first available, update the mask if (got_waiting[bank_id]) { // make sure this rank is not currently refreshing. - assert(ranks[i]->isAvailable()); + assert(ranks[i]->inRefIdleState()); // simplistic approximation of when the bank can issue // an activate, ignoring any rank-to-rank switching // cost in this calculation @@ -2178,7 +2182,7 @@ DRAMCtrl::Rank::processPowerEvent() } else if (pwrState == PWR_IDLE) { DPRINTF(DRAMState, "All banks precharged\n"); if (prev_state == PWR_SREF) { - // set refresh state to REF_SREF_EXIT, ensuring isAvailable + // set refresh state to REF_SREF_EXIT, ensuring inRefIdleState // continues to return false during tXS after SREF exit // Schedule a refresh which kicks things back into action // when it finishes @@ -2235,47 +2239,46 @@ DRAMCtrl::Rank::updatePowerStats() // 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(); - Data::MemoryPowerModel::Power rank_power = - power.powerlib.getPower(); - - actEnergy = energy.act_energy * memory.devicesPerRank; - preEnergy = energy.pre_energy * memory.devicesPerRank; - readEnergy = energy.read_energy * memory.devicesPerRank; - writeEnergy = energy.write_energy * memory.devicesPerRank; - refreshEnergy = energy.ref_energy * memory.devicesPerRank; - actBackEnergy = energy.act_stdby_energy * memory.devicesPerRank; - preBackEnergy = energy.pre_stdby_energy * memory.devicesPerRank; - actPowerDownEnergy = energy.f_act_pd_energy * memory.devicesPerRank; - prePowerDownEnergy = energy.f_pre_pd_energy * memory.devicesPerRank; - selfRefreshEnergy = energy.sref_energy * memory.devicesPerRank; - totalEnergy = energy.total_energy * memory.devicesPerRank; - averagePower = rank_power.average_power * memory.devicesPerRank; + // Call the function that calculates window energy at intermediate update + // events like at refresh, stats dump as well as at simulation exit. + // Window starts at the last time the calcWindowEnergy function was called + // and is upto current time. + power.powerlib.calcWindowEnergy(divCeil(curTick(), memory.tCK) - + memory.timeStampOffset); + + // Get the energy from DRAMPower + Data::MemoryPowerModel::Energy energy = power.powerlib.getEnergy(); + + // The energy components inside the power lib are calculated over + // the window so accumulate into the corresponding gem5 stat + actEnergy += energy.act_energy * memory.devicesPerRank; + preEnergy += energy.pre_energy * memory.devicesPerRank; + readEnergy += energy.read_energy * memory.devicesPerRank; + writeEnergy += energy.write_energy * memory.devicesPerRank; + refreshEnergy += energy.ref_energy * memory.devicesPerRank; + actBackEnergy += energy.act_stdby_energy * memory.devicesPerRank; + preBackEnergy += energy.pre_stdby_energy * memory.devicesPerRank; + actPowerDownEnergy += energy.f_act_pd_energy * memory.devicesPerRank; + prePowerDownEnergy += energy.f_pre_pd_energy * memory.devicesPerRank; + selfRefreshEnergy += energy.sref_energy * memory.devicesPerRank; + + // Accumulate window energy into the total energy. + totalEnergy += energy.window_energy * memory.devicesPerRank; + // Average power must not be accumulated but calculated over the time + // since last stats reset. SimClock::Frequency is tick period not tick + // frequency. + // energy (pJ) 1e-9 + // power (mW) = ----------- * ---------- + // time (tick) tick_frequency + averagePower = (totalEnergy.value() / + (curTick() - memory.lastStatsResetTick)) * + (SimClock::Frequency / 1000000000.0); } void DRAMCtrl::Rank::computeStats() { - DPRINTF(DRAM,"Computing final stats\n"); - - // Force DRAM power to update counters based on time spent in - // current state up to curTick() - cmdList.push_back(Command(MemCommand::NOP, 0, curTick())); + DPRINTF(DRAM,"Computing stats due to a dump callback\n"); // Update the stats updatePowerStats(); @@ -2287,6 +2290,16 @@ DRAMCtrl::Rank::computeStats() } void +DRAMCtrl::Rank::resetStats() { + // The only way to clear the counters in DRAMPower is to call + // calcWindowEnergy function as that then calls clearCounters. The + // clearCounters method itself is private. + power.powerlib.calcWindowEnergy(divCeil(curTick(), memory.tCK) - + memory.timeStampOffset); + +} + +void DRAMCtrl::Rank::regStats() { using namespace Stats; @@ -2355,6 +2368,7 @@ DRAMCtrl::Rank::regStats() .desc("Total Idle time Per DRAM Rank"); registerDumpCallback(new RankDumpCallback(this)); + registerResetCallback(new RankResetCallback(this)); } void DRAMCtrl::regStats() @@ -2367,6 +2381,8 @@ DRAMCtrl::regStats() r->regStats(); } + registerResetCallback(new MemResetCallback(this)); + readReqs .name(name() + ".readReqs") .desc("Number of read requests accepted"); @@ -2672,9 +2688,11 @@ 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; + // then verify that the power state is IDLE ensuring all banks are + // closed and rank is not in a low power state. Also verify that rank + // is idle from a refresh point of view. + all_ranks_drained = r->inPwrIdleState() && r->inRefIdleState() && + all_ranks_drained; } return all_ranks_drained; } diff --git a/src/mem/dram_ctrl.hh b/src/mem/dram_ctrl.hh index 226897b7e..467cfe898 100644 --- a/src/mem/dram_ctrl.hh +++ b/src/mem/dram_ctrl.hh @@ -43,6 +43,7 @@ * Omar Naji * Matthias Jung * Wendy Elsasser + * Radhika Jagtap */ /** @@ -472,15 +473,12 @@ class DRAMCtrl : public AbstractMemory void suspend(); /** - * Check if the current rank is available for scheduling. - * Rank will be unavailable if refresh is ongoing. - * This includes refresh events explicitly scheduled from the the - * controller or memory initiated events which will occur during - * self-refresh mode. + * Check if there is no refresh and no preparation of refresh ongoing + * i.e. the refresh state machine is in idle * * @param Return true if the rank is idle from a refresh point of view */ - bool isAvailable() const { return refreshState == REF_IDLE; } + bool inRefIdleState() const { return refreshState == REF_IDLE; } /** * Check if the current rank has all banks closed and is not @@ -539,6 +537,11 @@ class DRAMCtrl : public AbstractMemory void computeStats(); /** + * Reset stats on a stats event + */ + void resetStats(); + + /** * Schedule a transition to power-down (sleep) * * @param pwr_state Power state to transition to @@ -575,10 +578,12 @@ class DRAMCtrl : public AbstractMemory }; - // define the process to compute stats on simulation exit - // defined per rank as the per rank stats are based on state - // transition and periodically updated, requiring re-sync at - // exit. + /** + * Define the process to compute stats on a stats dump event, e.g. on + * simulation exit or intermediate stats dump. This is defined per rank + * as the per rank stats are based on state transition and periodically + * updated, requiring re-sync at exit. + */ class RankDumpCallback : public Callback { Rank *ranks; @@ -587,6 +592,30 @@ class DRAMCtrl : public AbstractMemory virtual void process() { ranks->computeStats(); }; }; + /** Define a process to clear power lib counters on a stats reset */ + class RankResetCallback : public Callback + { + private: + /** Pointer to the rank, thus we instantiate per rank */ + Rank *rank; + + public: + RankResetCallback(Rank *r) : rank(r) {} + virtual void process() { rank->resetStats(); }; + }; + + /** Define a process to store the time on a stats reset */ + class MemResetCallback : public Callback + { + private: + /** A reference to the DRAMCtrl instance */ + DRAMCtrl *mem; + + public: + MemResetCallback(DRAMCtrl *_mem) : mem(_mem) {} + virtual void process() { mem->lastStatsResetTick = curTick(); }; + }; + /** * A burst helper helps organize and manage a packet that is larger than * the DRAM burst size. A system packet that is larger than the burst size @@ -1039,6 +1068,9 @@ class DRAMCtrl : public AbstractMemory // timestamp offset uint64_t timeStampOffset; + /** The time when stats were last reset used to calculate average power */ + Tick lastStatsResetTick; + /** * Upstream caches need this packet until true is returned, so * hold it for deletion until a subsequent call |