summaryrefslogtreecommitdiff
path: root/src/mem/dram_ctrl.cc
diff options
context:
space:
mode:
authorRadhika Jagtap <radhika.jagtap@arm.com>2016-12-19 10:32:40 +0000
committerAndreas Sandberg <andreas.sandberg@arm.com>2017-11-16 16:39:19 +0000
commit290a7e7c5c059c1309ca3d02ea3158e2ca9ac338 (patch)
treef04a5c7aa0f5247d467e1bb8b2139d0e11baf532 /src/mem/dram_ctrl.cc
parent0757bef15d934b22555c396bcbcb91c0a1dffbe5 (diff)
downloadgem5-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/dram_ctrl.cc')
-rw-r--r--src/mem/dram_ctrl.cc126
1 files changed, 72 insertions, 54 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;
}