mem: DRAMPower trace output

This patch adds a DRAMPower flag to enable off-line DRAM power
analysis using the DRAMPower tool. A new DRAMPower flag is added
and a follow-on patch adds a Python script to post-process the output
and order it based on time stamps.

The long-term goal is to link DRAMPower as a library and provide the
commands through function calls to the model rather than first
printing and then parsing the commands. At the moment it is also up to
the user to ensure that the same DRAM configuration is used by the
gem5 controller model and DRAMPower.
This commit is contained in:
Andreas Hansson 2014-06-30 13:56:03 -04:00
parent b4ce51eb9e
commit 1f539ce4cc
3 changed files with 34 additions and 9 deletions

View file

@ -81,6 +81,7 @@ CompoundFlag('Bus', ['BaseBus', 'BusAddrRanges', 'CoherentBus',
DebugFlag('Bridge') DebugFlag('Bridge')
DebugFlag('CommMonitor') DebugFlag('CommMonitor')
DebugFlag('DRAM') DebugFlag('DRAM')
DebugFlag('DRAMPower')
DebugFlag('DRAMState') DebugFlag('DRAMState')
DebugFlag('LLSC') DebugFlag('LLSC')
DebugFlag('MMU') DebugFlag('MMU')

View file

@ -45,6 +45,7 @@
#include "base/bitfield.hh" #include "base/bitfield.hh"
#include "base/trace.hh" #include "base/trace.hh"
#include "debug/DRAM.hh" #include "debug/DRAM.hh"
#include "debug/DRAMPower.hh"
#include "debug/DRAMState.hh" #include "debug/DRAMState.hh"
#include "debug/Drain.hh" #include "debug/Drain.hh"
#include "mem/dram_ctrl.hh" #include "mem/dram_ctrl.hh"
@ -782,8 +783,11 @@ DRAMCtrl::activateBank(Bank& bank, Tick act_tick, uint32_t row)
++numBanksActive; ++numBanksActive;
assert(numBanksActive <= banksPerRank * ranksPerChannel); assert(numBanksActive <= banksPerRank * ranksPerChannel);
DPRINTF(DRAM, "Activate bank at tick %lld, now got %d active\n", DPRINTF(DRAM, "Activate bank %d, rank %d at tick %lld, now got %d active\n",
act_tick, numBanksActive); bank.bank, bank.rank, act_tick, numBanksActive);
DPRINTF(DRAMPower, "%llu,ACT,%d,%d\n", divCeil(act_tick, tCK), bank.bank,
bank.rank);
// The next access has to respect tRAS for this bank // The next access has to respect tRAS for this bank
bank.preAllowedAt = act_tick + tRAS; bank.preAllowedAt = act_tick + tRAS;
@ -851,7 +855,7 @@ DRAMCtrl::processActivateEvent()
} }
void void
DRAMCtrl::prechargeBank(Bank& bank, Tick pre_at) DRAMCtrl::prechargeBank(Bank& bank, Tick pre_at, bool trace)
{ {
// make sure the bank has an open row // make sure the bank has an open row
assert(bank.openRow != Bank::NO_ROW); assert(bank.openRow != Bank::NO_ROW);
@ -872,8 +876,12 @@ DRAMCtrl::prechargeBank(Bank& bank, Tick pre_at)
assert(numBanksActive != 0); assert(numBanksActive != 0);
--numBanksActive; --numBanksActive;
DPRINTF(DRAM, "Precharging bank at tick %lld, now got %d active\n", DPRINTF(DRAM, "Precharging bank %d, rank %d at tick %lld, now got "
pre_at, numBanksActive); "%d active\n", bank.bank, bank.rank, pre_at, numBanksActive);
if (trace)
DPRINTF(DRAMPower, "%llu,PRE,%d,%d\n", divCeil(pre_at, tCK),
bank.bank, bank.rank);
// if we look at the current number of active banks we might be // if we look at the current number of active banks we might be
// tempted to think the DRAM is now idle, however this can be // tempted to think the DRAM is now idle, however this can be
@ -1011,10 +1019,15 @@ DRAMCtrl::doDRAMAccess(DRAMPacket* dram_pkt)
(got_bank_conflict || pageMgmt == Enums::close_adaptive); (got_bank_conflict || pageMgmt == Enums::close_adaptive);
} }
// DRAMPower trace command to be written
std::string mem_cmd = dram_pkt->isRead ? "RD" : "WR";
// if this access should use auto-precharge, then we are // if this access should use auto-precharge, then we are
// closing the row // closing the row
if (auto_precharge) { if (auto_precharge) {
prechargeBank(bank, std::max(curTick(), bank.preAllowedAt)); prechargeBank(bank, std::max(curTick(), bank.preAllowedAt), false);
mem_cmd.append("A");
DPRINTF(DRAM, "Auto-precharged bank: %d\n", dram_pkt->bankId); DPRINTF(DRAM, "Auto-precharged bank: %d\n", dram_pkt->bankId);
} }
@ -1025,6 +1038,9 @@ DRAMCtrl::doDRAMAccess(DRAMPacket* dram_pkt)
DPRINTF(DRAM, "Access to %lld, ready at %lld bus busy until %lld.\n", DPRINTF(DRAM, "Access to %lld, ready at %lld bus busy until %lld.\n",
dram_pkt->addr, dram_pkt->readyTime, busBusyUntil); dram_pkt->addr, dram_pkt->readyTime, busBusyUntil);
DPRINTF(DRAMPower, "%llu,%s,%d,%d\n", divCeil(cmd_at, tCK), mem_cmd,
dram_pkt->bank, dram_pkt->rank);
// Update the minimum timing between the requests, this is a // Update the minimum timing between the requests, this is a
// conservative estimate of when we have to schedule the next // conservative estimate of when we have to schedule the next
// request to not introduce any unecessary bubbles. In most cases // request to not introduce any unecessary bubbles. In most cases
@ -1315,7 +1331,7 @@ DRAMCtrl::processRefreshEvent()
for (int i = 0; i < ranksPerChannel; i++) { for (int i = 0; i < ranksPerChannel; i++) {
for (int j = 0; j < banksPerRank; j++) { for (int j = 0; j < banksPerRank; j++) {
if (banks[i][j].openRow != Bank::NO_ROW) { if (banks[i][j].openRow != Bank::NO_ROW) {
prechargeBank(banks[i][j], pre_at); prechargeBank(banks[i][j], pre_at, false);
} else { } else {
banks[i][j].actAllowedAt = banks[i][j].actAllowedAt =
std::max(banks[i][j].actAllowedAt, act_allowed_at); std::max(banks[i][j].actAllowedAt, act_allowed_at);
@ -1323,6 +1339,10 @@ DRAMCtrl::processRefreshEvent()
std::max(banks[i][j].preAllowedAt, pre_at); std::max(banks[i][j].preAllowedAt, pre_at);
} }
} }
// at the moment this affects all ranks
DPRINTF(DRAMPower, "%llu,PREA,0,%d\n", divCeil(pre_at, tCK),
i);
} }
} else { } else {
DPRINTF(DRAM, "All banks already precharged, starting refresh\n"); DPRINTF(DRAM, "All banks already precharged, starting refresh\n");
@ -1354,6 +1374,9 @@ DRAMCtrl::processRefreshEvent()
for (int j = 0; j < banksPerRank; j++) { for (int j = 0; j < banksPerRank; j++) {
banks[i][j].actAllowedAt = ref_done_at; banks[i][j].actAllowedAt = ref_done_at;
} }
// at the moment this affects all ranks
DPRINTF(DRAMPower, "%llu,REF,0,%d\n", divCeil(curTick(), tCK), i);
} }
// make sure we did not wait so long that we cannot make up // make sure we did not wait so long that we cannot make up

View file

@ -401,10 +401,11 @@ class DRAMCtrl : public AbstractMemory
* done. This will also deal with any stats related to the * done. This will also deal with any stats related to the
* accesses to the open page. * accesses to the open page.
* *
* @param bank The bank to precharge * @param bank_ref The bank to precharge
* @param pre_at Time when the precharge takes place * @param pre_at Time when the precharge takes place
* @param trace Is this an auto precharge then do not add to trace
*/ */
void prechargeBank(Bank& bank, Tick pre_at); void prechargeBank(Bank& bank_ref, Tick pre_at, bool trace = true);
/** /**
* Used for debugging to observe the contents of the queues. * Used for debugging to observe the contents of the queues.