diff options
-rw-r--r-- | src/mem/dram_ctrl.cc | 149 | ||||
-rw-r--r-- | src/mem/dram_ctrl.hh | 45 |
2 files changed, 180 insertions, 14 deletions
diff --git a/src/mem/dram_ctrl.cc b/src/mem/dram_ctrl.cc index 198cb52a4..eac9ca353 100644 --- a/src/mem/dram_ctrl.cc +++ b/src/mem/dram_ctrl.cc @@ -52,6 +52,7 @@ #include "sim/system.hh" using namespace std; +using namespace Data; DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) : AbstractMemory(p), @@ -90,11 +91,18 @@ DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) : busBusyUntil(0), refreshDueAt(0), refreshState(REF_IDLE), pwrStateTrans(PWR_IDLE), pwrState(PWR_IDLE), prevArrival(0), nextReqTime(0), pwrStateTick(0), numBanksActive(0), - activeRank(0) + activeRank(0), timeStampOffset(0) { // create the bank states based on the dimensions of the ranks and // banks banks.resize(ranksPerChannel); + + //create list of drampower objects. For each rank 1 drampower instance. + for (int i = 0; i < ranksPerChannel; i++) { + DRAMPower drampower = DRAMPower(p, false); + rankPower.emplace_back(drampower); + } + actTicks.resize(ranksPerChannel); for (size_t c = 0; c < ranksPerChannel; ++c) { banks[c].resize(banksPerRank); @@ -227,6 +235,8 @@ DRAMCtrl::init() void DRAMCtrl::startup() { + // timestamp offset should be in clock cycles for DRAMPower + timeStampOffset = divCeil(curTick(), tCK); // update the start tick for the precharge accounting to the // current tick pwrStateTick = curTick(); @@ -861,8 +871,12 @@ DRAMCtrl::activateBank(Bank& bank, Tick act_tick, uint32_t row) DPRINTF(DRAM, "Activate bank %d, rank %d at tick %lld, now got %d active\n", bank.bank, bank.rank, act_tick, numBanksActive); - DPRINTF(DRAMPower, "%llu,ACT,%d,%d\n", divCeil(act_tick, tCK), bank.bank, - bank.rank); + rankPower[bank.rank].powerlib.doCommand(MemCommand::ACT, bank.bank, + divCeil(act_tick, tCK) - + timeStampOffset); + + DPRINTF(DRAMPower, "%llu,ACT,%d,%d\n", divCeil(act_tick, tCK) - + timeStampOffset, bank.bank, bank.rank); // The next access has to respect tRAS for this bank bank.preAllowedAt = act_tick + tRAS; @@ -965,10 +979,14 @@ DRAMCtrl::prechargeBank(Bank& bank, Tick pre_at, bool trace) DPRINTF(DRAM, "Precharging bank %d, rank %d at tick %lld, now got " "%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 (trace) { + rankPower[bank.rank].powerlib.doCommand(MemCommand::PRE, bank.bank, + divCeil(pre_at, tCK) - + timeStampOffset); + DPRINTF(DRAMPower, "%llu,PRE,%d,%d\n", divCeil(pre_at, tCK) - + timeStampOffset, bank.bank, bank.rank); + } // 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 // undone by an activate that is scheduled to happen before we @@ -1140,12 +1158,16 @@ DRAMCtrl::doDRAMAccess(DRAMPacket* dram_pkt) // DRAMPower trace command to be written std::string mem_cmd = dram_pkt->isRead ? "RD" : "WR"; + // MemCommand required for DRAMPower library + MemCommand::cmds command = (mem_cmd == "RD") ? MemCommand::RD : + MemCommand::WR; + // if this access should use auto-precharge, then we are // closing the row if (auto_precharge) { - prechargeBank(bank, std::max(curTick(), bank.preAllowedAt), false); - - mem_cmd.append("A"); + // if auto-precharge push a PRE command at the correct tick to the + // list used by DRAMPower library to calculate power + prechargeBank(bank, std::max(curTick(), bank.preAllowedAt)); DPRINTF(DRAM, "Auto-precharged bank: %d\n", dram_pkt->bankId); } @@ -1156,8 +1178,12 @@ DRAMCtrl::doDRAMAccess(DRAMPacket* dram_pkt) DPRINTF(DRAM, "Access to %lld, ready at %lld bus busy until %lld.\n", 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); + rankPower[dram_pkt->rank].powerlib.doCommand(command, dram_pkt->bank, + divCeil(cmd_at, tCK) - + timeStampOffset); + + DPRINTF(DRAMPower, "%llu,%s,%d,%d\n", divCeil(cmd_at, tCK) - + timeStampOffset, mem_cmd, dram_pkt->bank, dram_pkt->rank); // Update the minimum timing between the requests, this is a // conservative estimate of when we have to schedule the next @@ -1510,8 +1536,12 @@ DRAMCtrl::processRefreshEvent() } // at the moment this affects all ranks - DPRINTF(DRAMPower, "%llu,PREA,0,%d\n", divCeil(pre_at, tCK), - i); + rankPower[i].powerlib.doCommand(MemCommand::PREA, 0, + divCeil(pre_at, tCK) - + timeStampOffset); + + DPRINTF(DRAMPower, "%llu,PREA,0,%d\n", divCeil(pre_at, tCK) - + timeStampOffset, i); } } else { DPRINTF(DRAM, "All banks already precharged, starting refresh\n"); @@ -1545,7 +1575,33 @@ DRAMCtrl::processRefreshEvent() } // at the moment this affects all ranks - DPRINTF(DRAMPower, "%llu,REF,0,%d\n", divCeil(curTick(), tCK), i); + rankPower[i].powerlib.doCommand(MemCommand::REF, 0, + divCeil(curTick(), tCK) - + timeStampOffset); + + // at the moment sort the list of commands and update the counters + // for DRAMPower libray when doing a refresh + sort(rankPower[i].powerlib.cmdList.begin(), + rankPower[i].powerlib.cmdList.end(), DRAMCtrl::sortTime); + + // 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. + rankPower[i].powerlib.updateCounters(false); + + // call the energy function + rankPower[i].powerlib.calcEnergy(); + + // Update the stats + updatePowerStats(i); + + DPRINTF(DRAMPower, "%llu,REF,0,%d\n", divCeil(curTick(), tCK) - + timeStampOffset, i); } // make sure we did not wait so long that we cannot make up @@ -1646,6 +1702,26 @@ DRAMCtrl::processPowerEvent() } void +DRAMCtrl::updatePowerStats(uint8_t rank) +{ + // Get the energy and power from DRAMPower + Data::MemoryPowerModel::Energy energy = + rankPower[rank].powerlib.getEnergy(); + Data::MemoryPowerModel::Power power = + rankPower[rank].powerlib.getPower(); + + actEnergy[rank] = energy.act_energy * devicesPerRank; + preEnergy[rank] = energy.pre_energy * devicesPerRank; + readEnergy[rank] = energy.read_energy * devicesPerRank; + writeEnergy[rank] = energy.write_energy * devicesPerRank; + refreshEnergy[rank] = energy.ref_energy * devicesPerRank; + actBackEnergy[rank] = energy.act_stdby_energy * devicesPerRank; + preBackEnergy[rank] = energy.pre_stdby_energy * devicesPerRank; + totalEnergy[rank] = energy.total_energy * devicesPerRank; + averagePower[rank] = power.average_power * devicesPerRank; +} + +void DRAMCtrl::regStats() { using namespace Stats; @@ -1909,6 +1985,51 @@ DRAMCtrl::regStats() pwrStateTime.subname(2, "PRE_PDN"); pwrStateTime.subname(3, "ACT"); pwrStateTime.subname(4, "ACT_PDN"); + + actEnergy + .init(ranksPerChannel) + .name(name() + ".actEnergy") + .desc("Energy for activate commands per rank (pJ)"); + + preEnergy + .init(ranksPerChannel) + .name(name() + ".preEnergy") + .desc("Energy for precharge commands per rank (pJ)"); + + readEnergy + .init(ranksPerChannel) + .name(name() + ".readEnergy") + .desc("Energy for read commands per rank (pJ)"); + + writeEnergy + .init(ranksPerChannel) + .name(name() + ".writeEnergy") + .desc("Energy for write commands per rank (pJ)"); + + refreshEnergy + .init(ranksPerChannel) + .name(name() + ".refreshEnergy") + .desc("Energy for refresh commands per rank (pJ)"); + + actBackEnergy + .init(ranksPerChannel) + .name(name() + ".actBackEnergy") + .desc("Energy for active background per rank (pJ)"); + + preBackEnergy + .init(ranksPerChannel) + .name(name() + ".preBackEnergy") + .desc("Energy for precharge background per rank (pJ)"); + + totalEnergy + .init(ranksPerChannel) + .name(name() + ".totalEnergy") + .desc("Total energy per rank (pJ)"); + + averagePower + .init(ranksPerChannel) + .name(name() + ".averagePower") + .desc("Core power per rank (mW)"); } void diff --git a/src/mem/dram_ctrl.hh b/src/mem/dram_ctrl.hh index cc2bd13fd..cb2197841 100644 --- a/src/mem/dram_ctrl.hh +++ b/src/mem/dram_ctrl.hh @@ -60,6 +60,7 @@ #include "mem/qport.hh" #include "params/DRAMCtrl.hh" #include "sim/eventq.hh" +#include "mem/drampower.hh" /** * The DRAM controller is a single-channel memory controller capturing @@ -677,6 +678,20 @@ class DRAMCtrl : public AbstractMemory Stats::Formula pageHitRate; Stats::Vector pwrStateTime; + //Command energies + Stats::Vector actEnergy; + Stats::Vector preEnergy; + Stats::Vector readEnergy; + Stats::Vector writeEnergy; + Stats::Vector refreshEnergy; + //Active Background Energy + Stats::Vector actBackEnergy; + //Precharge Background Energy + Stats::Vector preBackEnergy; + Stats::Vector totalEnergy; + //Power Consumed + Stats::Vector averagePower; + // Track when we transitioned to the current power state Tick pwrStateTick; @@ -686,12 +701,42 @@ class DRAMCtrl : public AbstractMemory // Holds the value of the rank of burst issued uint8_t activeRank; + // timestamp offset + uint64_t timeStampOffset; + /** @todo this is a temporary workaround until the 4-phase code is * committed. upstream caches needs this packet until true is returned, so * hold onto it for deletion until a subsequent call */ std::vector<PacketPtr> pendingDelete; + // One DRAMPower instance per rank + std::vector<DRAMPower> rankPower; + + /** + * This function increments the energy when called. If stats are + * dumped periodically, note accumulated energy values will + * appear in the stats (even if the stats are reset). This is a + * result of the energy values coming from DRAMPower, and there + * is currently no support for resetting the state. + * + * @param rank Currrent rank + */ + void updatePowerStats(uint8_t rank); + + /** + * Function for sorting commands in the command list of DRAMPower. + * + * @param a Memory Command in command list of DRAMPower library + * @param next Memory Command in command list of DRAMPower + * @return true if timestamp of Command 1 < timestamp of Command 2 + */ + static bool sortTime(const Data::MemCommand& m1, + const Data::MemCommand& m2) { + return m1.getTime() < m2.getTime(); + }; + + public: void regStats(); |