From 76384ec3ff2a52898aa35a27d337194ae557648a Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Mon, 23 Sep 2019 18:20:23 +0100 Subject: [PATCH] mem: Convert DRAM controller to new-style stats Note that this changes the stat format used by the DRAM controller. Previously, it would have a structure looking a bit like this: - system - dram: Main DRAM controller - dram_0: Rank 0 - dram_1: Rank 1 This structure can't be replicated with new-world stats since stats are confined to the SimObject name space. This means that the new structure looks like this: - system - dram: Main DRAM controller - rank0: Rank 0 - rank1: Rank 1 Change-Id: I7435cfaf137c94b0c18de619d816362dd0da8125 Signed-off-by: Andreas Sandberg Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21142 Maintainer: Nikos Nikoleris Tested-by: kokoro Reviewed-by: Daniel Carvalho Reviewed-by: Wendy Elsasser --- src/mem/abstract_mem.cc | 131 ++++---- src/mem/abstract_mem.hh | 56 ++-- src/mem/dram_ctrl.cc | 711 +++++++++++++++++----------------------- src/mem/dram_ctrl.hh | 301 ++++++++--------- src/mem/qos/mem_ctrl.cc | 118 ++++--- src/mem/qos/mem_ctrl.hh | 51 +-- 6 files changed, 648 insertions(+), 720 deletions(-) diff --git a/src/mem/abstract_mem.cc b/src/mem/abstract_mem.cc index 6870ba38f..d913f05d3 100644 --- a/src/mem/abstract_mem.cc +++ b/src/mem/abstract_mem.cc @@ -62,7 +62,8 @@ AbstractMemory::AbstractMemory(const Params *p) : (MemBackdoor::Flags)(MemBackdoor::Readable | MemBackdoor::Writeable)), confTableReported(p->conf_table_reported), inAddrMap(p->in_addr_map), - kvmMap(p->kvm_map), _system(NULL) + kvmMap(p->kvm_map), _system(NULL), + stats(*this) { } @@ -88,110 +89,126 @@ AbstractMemory::setBackingStore(uint8_t* pmem_addr) pmemAddr = pmem_addr; } -void -AbstractMemory::regStats() +AbstractMemory::MemStats::MemStats(AbstractMemory &_mem) + : Stats::Group(&_mem), mem(_mem), + bytesRead(this, "bytes_read", + "Number of bytes read from this memory"), + bytesInstRead(this, "bytes_inst_read", + "Number of instructions bytes read from this memory"), + bytesWritten(this, "bytes_written", + "Number of bytes written to this memory"), + numReads(this, "num_reads", + "Number of read requests responded to by this memory"), + numWrites(this, "num_writes", + "Number of write requests responded to by this memory"), + numOther(this, "num_other", + "Number of other requests responded to by this memory"), + bwRead(this, "bw_read", + "Total read bandwidth from this memory (bytes/s)"), + bwInstRead(this, "bw_inst_read", + "Instruction read bandwidth from this memory (bytes/s)"), + bwWrite(this, "bw_write", + "Write bandwidth from this memory (bytes/s)"), + bwTotal(this, "bw_total", + "Total bandwidth to/from this memory (bytes/s)") { - ClockedObject::regStats(); +} +void +AbstractMemory::MemStats::regStats() +{ using namespace Stats; - assert(system()); + Stats::Group::regStats(); + + System *sys = mem.system(); + assert(sys); + const auto max_masters = sys->maxMasters(); bytesRead - .init(system()->maxMasters()) - .name(name() + ".bytes_read") - .desc("Number of bytes read from this memory") + .init(max_masters) .flags(total | nozero | nonan) ; - for (int i = 0; i < system()->maxMasters(); i++) { - bytesRead.subname(i, system()->getMasterName(i)); + for (int i = 0; i < max_masters; i++) { + bytesRead.subname(i, sys->getMasterName(i)); } + bytesInstRead - .init(system()->maxMasters()) - .name(name() + ".bytes_inst_read") - .desc("Number of instructions bytes read from this memory") + .init(max_masters) .flags(total | nozero | nonan) ; - for (int i = 0; i < system()->maxMasters(); i++) { - bytesInstRead.subname(i, system()->getMasterName(i)); + for (int i = 0; i < max_masters; i++) { + bytesInstRead.subname(i, sys->getMasterName(i)); } + bytesWritten - .init(system()->maxMasters()) - .name(name() + ".bytes_written") - .desc("Number of bytes written to this memory") + .init(max_masters) .flags(total | nozero | nonan) ; - for (int i = 0; i < system()->maxMasters(); i++) { - bytesWritten.subname(i, system()->getMasterName(i)); + for (int i = 0; i < max_masters; i++) { + bytesWritten.subname(i, sys->getMasterName(i)); } + numReads - .init(system()->maxMasters()) - .name(name() + ".num_reads") - .desc("Number of read requests responded to by this memory") + .init(max_masters) .flags(total | nozero | nonan) ; - for (int i = 0; i < system()->maxMasters(); i++) { - numReads.subname(i, system()->getMasterName(i)); + for (int i = 0; i < max_masters; i++) { + numReads.subname(i, sys->getMasterName(i)); } + numWrites - .init(system()->maxMasters()) - .name(name() + ".num_writes") - .desc("Number of write requests responded to by this memory") + .init(max_masters) .flags(total | nozero | nonan) ; - for (int i = 0; i < system()->maxMasters(); i++) { - numWrites.subname(i, system()->getMasterName(i)); + for (int i = 0; i < max_masters; i++) { + numWrites.subname(i, sys->getMasterName(i)); } + numOther - .init(system()->maxMasters()) - .name(name() + ".num_other") - .desc("Number of other requests responded to by this memory") + .init(max_masters) .flags(total | nozero | nonan) ; - for (int i = 0; i < system()->maxMasters(); i++) { - numOther.subname(i, system()->getMasterName(i)); + for (int i = 0; i < max_masters; i++) { + numOther.subname(i, sys->getMasterName(i)); } + bwRead - .name(name() + ".bw_read") - .desc("Total read bandwidth from this memory (bytes/s)") .precision(0) .prereq(bytesRead) .flags(total | nozero | nonan) ; - for (int i = 0; i < system()->maxMasters(); i++) { - bwRead.subname(i, system()->getMasterName(i)); + for (int i = 0; i < max_masters; i++) { + bwRead.subname(i, sys->getMasterName(i)); } bwInstRead - .name(name() + ".bw_inst_read") - .desc("Instruction read bandwidth from this memory (bytes/s)") .precision(0) .prereq(bytesInstRead) .flags(total | nozero | nonan) ; - for (int i = 0; i < system()->maxMasters(); i++) { - bwInstRead.subname(i, system()->getMasterName(i)); + for (int i = 0; i < max_masters; i++) { + bwInstRead.subname(i, sys->getMasterName(i)); } + bwWrite - .name(name() + ".bw_write") - .desc("Write bandwidth from this memory (bytes/s)") .precision(0) .prereq(bytesWritten) .flags(total | nozero | nonan) ; - for (int i = 0; i < system()->maxMasters(); i++) { - bwWrite.subname(i, system()->getMasterName(i)); + for (int i = 0; i < max_masters; i++) { + bwWrite.subname(i, sys->getMasterName(i)); } + bwTotal - .name(name() + ".bw_total") - .desc("Total bandwidth to/from this memory (bytes/s)") .precision(0) .prereq(bwTotal) .flags(total | nozero | nonan) ; - for (int i = 0; i < system()->maxMasters(); i++) { - bwTotal.subname(i, system()->getMasterName(i)); + for (int i = 0; i < max_masters; i++) { + bwTotal.subname(i, sys->getMasterName(i)); } + bwRead = bytesRead / simSeconds; bwInstRead = bytesInstRead / simSeconds; bwWrite = bytesWritten / simSeconds; @@ -384,7 +401,7 @@ AbstractMemory::access(PacketPtr pkt) assert(!pkt->req->isInstFetch()); TRACE_PACKET("Read/Write"); - numOther[pkt->req->masterId()]++; + stats.numOther[pkt->req->masterId()]++; } } else if (pkt->isRead()) { assert(!pkt->isWrite()); @@ -398,10 +415,10 @@ AbstractMemory::access(PacketPtr pkt) pkt->setData(hostAddr); } TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read"); - numReads[pkt->req->masterId()]++; - bytesRead[pkt->req->masterId()] += pkt->getSize(); + stats.numReads[pkt->req->masterId()]++; + stats.bytesRead[pkt->req->masterId()] += pkt->getSize(); if (pkt->req->isInstFetch()) - bytesInstRead[pkt->req->masterId()] += pkt->getSize(); + stats.bytesInstRead[pkt->req->masterId()] += pkt->getSize(); } else if (pkt->isInvalidate() || pkt->isClean()) { assert(!pkt->isWrite()); // in a fastmem system invalidating and/or cleaning packets @@ -417,8 +434,8 @@ AbstractMemory::access(PacketPtr pkt) } assert(!pkt->req->isInstFetch()); TRACE_PACKET("Write"); - numWrites[pkt->req->masterId()]++; - bytesWritten[pkt->req->masterId()] += pkt->getSize(); + stats.numWrites[pkt->req->masterId()]++; + stats.bytesWritten[pkt->req->masterId()] += pkt->getSize(); } } else { panic("Unexpected packet %s", pkt->print()); diff --git a/src/mem/abstract_mem.hh b/src/mem/abstract_mem.hh index 8b944b981..655fc0115 100644 --- a/src/mem/abstract_mem.hh +++ b/src/mem/abstract_mem.hh @@ -161,33 +161,41 @@ class AbstractMemory : public ClockedObject } } - /** Number of total bytes read from this memory */ - Stats::Vector bytesRead; - /** Number of instruction bytes read from this memory */ - Stats::Vector bytesInstRead; - /** Number of bytes written to this memory */ - Stats::Vector bytesWritten; - /** Number of read requests */ - Stats::Vector numReads; - /** Number of write requests */ - Stats::Vector numWrites; - /** Number of other requests */ - Stats::Vector numOther; - /** Read bandwidth from this memory */ - Stats::Formula bwRead; - /** Read bandwidth from this memory */ - Stats::Formula bwInstRead; - /** Write bandwidth from this memory */ - Stats::Formula bwWrite; - /** Total bandwidth from this memory */ - Stats::Formula bwTotal; - /** Pointor to the System object. * This is used for getting the number of masters in the system which is * needed when registering stats */ System *_system; + struct MemStats : public Stats::Group { + MemStats(AbstractMemory &mem); + + void regStats() override; + + const AbstractMemory &mem; + + /** Number of total bytes read from this memory */ + Stats::Vector bytesRead; + /** Number of instruction bytes read from this memory */ + Stats::Vector bytesInstRead; + /** Number of bytes written to this memory */ + Stats::Vector bytesWritten; + /** Number of read requests */ + Stats::Vector numReads; + /** Number of write requests */ + Stats::Vector numWrites; + /** Number of other requests */ + Stats::Vector numOther; + /** Read bandwidth from this memory */ + Stats::Formula bwRead; + /** Read bandwidth from this memory */ + Stats::Formula bwInstRead; + /** Write bandwidth from this memory */ + Stats::Formula bwWrite; + /** Total bandwidth from this memory */ + Stats::Formula bwTotal; + } stats; + private: @@ -318,12 +326,6 @@ class AbstractMemory : public ClockedObject * @param pkt Packet performing the access */ void functionalAccess(PacketPtr pkt); - - /** - * Register Statistics - */ - void regStats() override; - }; #endif //__MEM_ABSTRACT_MEMORY_HH__ diff --git a/src/mem/dram_ctrl.cc b/src/mem/dram_ctrl.cc index 06c540ba6..1352dbfbe 100644 --- a/src/mem/dram_ctrl.cc +++ b/src/mem/dram_ctrl.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2018 ARM Limited + * Copyright (c) 2010-2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -96,7 +96,9 @@ DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) : frontendLatency(p->static_frontend_latency), backendLatency(p->static_backend_latency), nextBurstAt(0), prevArrival(0), - nextReqTime(0), activeRank(0), timeStampOffset(0), + nextReqTime(0), + stats(*this), + activeRank(0), timeStampOffset(0), lastStatsResetTick(0), enableDRAMPowerdown(p->enable_dram_powerdown) { // sanity check the ranks since we rely on bit slicing for the @@ -429,9 +431,9 @@ DRAMCtrl::addToReadQueue(PacketPtr pkt, unsigned int pktCount) for (int cnt = 0; cnt < pktCount; ++cnt) { unsigned size = std::min((addr | (burstSize - 1)) + 1, pkt->getAddr() + pkt->getSize()) - addr; - readPktSize[ceilLog2(size)]++; - readBursts++; - masterReadAccesses[pkt->masterId()]++; + stats.readPktSize[ceilLog2(size)]++; + stats.readBursts++; + stats.masterReadAccesses[pkt->masterId()]++; // First check write buffer to see if the data is already at // the controller @@ -448,13 +450,13 @@ DRAMCtrl::addToReadQueue(PacketPtr pkt, unsigned int pktCount) ((addr + size) <= (p->addr + p->size))) { foundInWrQ = true; - servicedByWrQ++; + stats.servicedByWrQ++; pktsServicedByWrQ++; DPRINTF(DRAM, "Read to addr %lld with size %d serviced by " "write queue\n", addr, size); - bytesReadWrQ += burstSize; + stats.bytesReadWrQ += burstSize; break; } } @@ -476,7 +478,7 @@ DRAMCtrl::addToReadQueue(PacketPtr pkt, unsigned int pktCount) dram_pkt->burstHelper = burst_helper; assert(!readQueueFull(1)); - rdQLenPdf[totalReadQueueSize + respQueue.size()]++; + stats.rdQLenPdf[totalReadQueueSize + respQueue.size()]++; DPRINTF(DRAM, "Adding to read queue\n"); @@ -489,7 +491,7 @@ DRAMCtrl::addToReadQueue(PacketPtr pkt, unsigned int pktCount) dram_pkt->addr, 1); // Update stats - avgRdQLen = totalReadQueueSize + respQueue.size(); + stats.avgRdQLen = totalReadQueueSize + respQueue.size(); } // Starting address of next dram pkt (aligend to burstSize boundary) @@ -527,9 +529,9 @@ DRAMCtrl::addToWriteQueue(PacketPtr pkt, unsigned int pktCount) for (int cnt = 0; cnt < pktCount; ++cnt) { unsigned size = std::min((addr | (burstSize - 1)) + 1, pkt->getAddr() + pkt->getSize()) - addr; - writePktSize[ceilLog2(size)]++; - writeBursts++; - masterWriteAccesses[pkt->masterId()]++; + stats.writePktSize[ceilLog2(size)]++; + stats.writeBursts++; + stats.masterWriteAccesses[pkt->masterId()]++; // see if we can merge with an existing item in the write // queue and keep track of whether we have merged or not @@ -542,7 +544,7 @@ DRAMCtrl::addToWriteQueue(PacketPtr pkt, unsigned int pktCount) DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size, false); assert(totalWriteQueueSize < writeBufferSize); - wrQLenPdf[totalWriteQueueSize]++; + stats.wrQLenPdf[totalWriteQueueSize]++; DPRINTF(DRAM, "Adding to write queue\n"); @@ -556,7 +558,7 @@ DRAMCtrl::addToWriteQueue(PacketPtr pkt, unsigned int pktCount) assert(totalWriteQueueSize == isInWriteQueue.size()); // Update stats - avgWrQLen = totalWriteQueueSize; + stats.avgWrQLen = totalWriteQueueSize; // increment write entries of the rank ++dram_pkt->rankRef.writeEntries; @@ -565,7 +567,7 @@ DRAMCtrl::addToWriteQueue(PacketPtr pkt, unsigned int pktCount) // keep track of the fact that this burst effectively // disappeared as it was merged with an existing one - mergedWrBursts++; + stats.mergedWrBursts++; } // Starting address of next dram pkt (aligend to burstSize boundary) @@ -627,7 +629,7 @@ DRAMCtrl::recvTimingReq(PacketPtr pkt) // Calc avg gap between requests if (prevArrival != 0) { - totGap += curTick() - prevArrival; + stats.totGap += curTick() - prevArrival; } prevArrival = curTick(); @@ -650,12 +652,12 @@ DRAMCtrl::recvTimingReq(PacketPtr pkt) DPRINTF(DRAM, "Write queue full, not accepting\n"); // remember that we have to retry this port retryWrReq = true; - numWrRetry++; + stats.numWrRetry++; return false; } else { addToWriteQueue(pkt, dram_pkt_count); - writeReqs++; - bytesWrittenSys += size; + stats.writeReqs++; + stats.bytesWrittenSys += size; } } else { assert(pkt->isRead()); @@ -664,12 +666,12 @@ DRAMCtrl::recvTimingReq(PacketPtr pkt) DPRINTF(DRAM, "Read queue full, not accepting\n"); // remember that we have to retry this port retryRdReq = true; - numRdRetry++; + stats.numRdRetry++; return false; } else { addToReadQueue(pkt, dram_pkt_count); - readReqs++; - bytesReadSys += size; + stats.readReqs++; + stats.bytesReadSys += size; } } @@ -1059,7 +1061,7 @@ DRAMCtrl::prechargeBank(Rank& rank_ref, Bank& bank, Tick pre_at, bool trace) // sample the bytes per activate here since we are closing // the page - bytesPerActivate.sample(bank.bytesAccessed); + stats.bytesPerActivate.sample(bank.bytesAccessed); bank.openRow = Bank::NO_ROW; @@ -1304,26 +1306,26 @@ DRAMCtrl::doDRAMAccess(DRAMPacket* dram_pkt) if (dram_pkt->isRead()) { ++readsThisTime; if (row_hit) - readRowHits++; - bytesReadDRAM += burstSize; - perBankRdBursts[dram_pkt->bankId]++; + stats.readRowHits++; + stats.bytesReadDRAM += burstSize; + stats.perBankRdBursts[dram_pkt->bankId]++; // Update latency stats - totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime; - masterReadTotalLat[dram_pkt->masterId()] += + stats.totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime; + stats.masterReadTotalLat[dram_pkt->masterId()] += dram_pkt->readyTime - dram_pkt->entryTime; - totBusLat += tBURST; - totQLat += cmd_at - dram_pkt->entryTime; - masterReadBytes[dram_pkt->masterId()] += dram_pkt->size; + stats.totBusLat += tBURST; + stats.totQLat += cmd_at - dram_pkt->entryTime; + stats.masterReadBytes[dram_pkt->masterId()] += dram_pkt->size; } else { ++writesThisTime; if (row_hit) - writeRowHits++; - bytesWritten += burstSize; - perBankWrBursts[dram_pkt->bankId]++; - masterWriteBytes[dram_pkt->masterId()] += dram_pkt->size; - masterWriteTotalLat[dram_pkt->masterId()] += + stats.writeRowHits++; + stats.bytesWritten += burstSize; + stats.perBankWrBursts[dram_pkt->bankId]++; + stats.masterWriteBytes[dram_pkt->masterId()] += dram_pkt->size; + stats.masterWriteTotalLat[dram_pkt->masterId()] += dram_pkt->readyTime - dram_pkt->entryTime; } } @@ -1351,13 +1353,13 @@ DRAMCtrl::processNextReqEvent() DPRINTF(DRAM, "Switching to writes after %d reads with %d reads " "waiting\n", readsThisTime, totalReadQueueSize); - rdPerTurnAround.sample(readsThisTime); + stats.rdPerTurnAround.sample(readsThisTime); readsThisTime = 0; } else { DPRINTF(DRAM, "Switching to reads after %d writes with %d writes " "waiting\n", writesThisTime, totalWriteQueueSize); - wrPerTurnAround.sample(writesThisTime); + stats.wrPerTurnAround.sample(writesThisTime); writesThisTime = 0; } } @@ -1732,7 +1734,8 @@ DRAMCtrl::Rank::Rank(DRAMCtrl& _memory, const DRAMCtrlParams* _p, int rank) prechargeEvent([this]{ processPrechargeEvent(); }, name()), refreshEvent([this]{ processRefreshEvent(); }, name()), powerEvent([this]{ processPowerEvent(); }, name()), - wakeUpEvent([this]{ processWakeUpEvent(); }, name()) + wakeUpEvent([this]{ processWakeUpEvent(); }, name()), + stats(_memory, *this) { for (int b = 0; b < _p->banks_per_rank; b++) { banks[b].bank = b; @@ -2237,12 +2240,12 @@ DRAMCtrl::Rank::processPowerEvent() PowerState prev_state = pwrState; // update the accounting - pwrStateTime[prev_state] += duration; + stats.memoryStateTime[prev_state] += duration; // track to total idle time if ((prev_state == PWR_PRE_PDN) || (prev_state == PWR_ACT_PDN) || (prev_state == PWR_SREF)) { - totalIdleTime += duration; + stats.totalIdleTime += duration; } pwrState = pwrStateTrans; @@ -2380,28 +2383,28 @@ DRAMCtrl::Rank::updatePowerStats() // 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; + stats.actEnergy += energy.act_energy * memory.devicesPerRank; + stats.preEnergy += energy.pre_energy * memory.devicesPerRank; + stats.readEnergy += energy.read_energy * memory.devicesPerRank; + stats.writeEnergy += energy.write_energy * memory.devicesPerRank; + stats.refreshEnergy += energy.ref_energy * memory.devicesPerRank; + stats.actBackEnergy += energy.act_stdby_energy * memory.devicesPerRank; + stats.preBackEnergy += energy.pre_stdby_energy * memory.devicesPerRank; + stats.actPowerDownEnergy += energy.f_act_pd_energy * memory.devicesPerRank; + stats.prePowerDownEnergy += energy.f_pre_pd_energy * memory.devicesPerRank; + stats.selfRefreshEnergy += energy.sref_energy * memory.devicesPerRank; // Accumulate window energy into the total energy. - totalEnergy += energy.window_energy * memory.devicesPerRank; + stats.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); + stats.averagePower = (stats.totalEnergy.value() / + (curTick() - memory.lastStatsResetTick)) * + (SimClock::Frequency / 1000000000.0); } void @@ -2413,9 +2416,8 @@ DRAMCtrl::Rank::computeStats() updatePowerStats(); // final update of power state times - pwrStateTime[pwrState] += (curTick() - pwrStateTick); + stats.memoryStateTime[pwrState] += (curTick() - pwrStateTick); pwrStateTick = curTick(); - } void @@ -2428,405 +2430,204 @@ DRAMCtrl::Rank::resetStats() { } -void -DRAMCtrl::Rank::regStats() +DRAMCtrl::DRAMStats::DRAMStats(DRAMCtrl &_dram) + : Stats::Group(&_dram), + dram(_dram), + + ADD_STAT(readReqs, "Number of read requests accepted"), + ADD_STAT(writeReqs, "Number of write requests accepted"), + + ADD_STAT(readBursts, + "Number of DRAM read bursts, " + "including those serviced by the write queue"), + ADD_STAT(writeBursts, + "Number of DRAM write bursts, " + "including those merged in the write queue"), + ADD_STAT(servicedByWrQ, + "Number of DRAM read bursts serviced by the write queue"), + ADD_STAT(mergedWrBursts, + "Number of DRAM write bursts merged with an existing one"), + + ADD_STAT(neitherReadNorWriteReqs, + "Number of requests that are neither read nor write"), + + ADD_STAT(perBankRdBursts, "Per bank write bursts"), + ADD_STAT(perBankWrBursts, "Per bank write bursts"), + + ADD_STAT(avgRdQLen, "Average read queue length when enqueuing"), + ADD_STAT(avgWrQLen, "Average write queue length when enqueuing"), + + ADD_STAT(totQLat, "Total ticks spent queuing"), + ADD_STAT(totBusLat, "Total ticks spent in databus transfers"), + ADD_STAT(totMemAccLat, + "Total ticks spent from burst creation until serviced " + "by the DRAM"), + ADD_STAT(avgQLat, "Average queueing delay per DRAM burst"), + ADD_STAT(avgBusLat, "Average bus latency per DRAM burst"), + ADD_STAT(avgMemAccLat, "Average memory access latency per DRAM burst"), + + ADD_STAT(numRdRetry, "Number of times read queue was full causing retry"), + ADD_STAT(numWrRetry, "Number of times write queue was full causing retry"), + + ADD_STAT(readRowHits, "Number of row buffer hits during reads"), + ADD_STAT(writeRowHits, "Number of row buffer hits during writes"), + ADD_STAT(readRowHitRate, "Row buffer hit rate for reads"), + ADD_STAT(writeRowHitRate, "Row buffer hit rate for writes"), + + ADD_STAT(readPktSize, "Read request sizes (log2)"), + ADD_STAT(writePktSize, "Write request sizes (log2)"), + + ADD_STAT(rdQLenPdf, "What read queue length does an incoming req see"), + ADD_STAT(wrQLenPdf, "What write queue length does an incoming req see"), + + ADD_STAT(bytesPerActivate, "Bytes accessed per row activation"), + + ADD_STAT(rdPerTurnAround, + "Reads before turning the bus around for writes"), + ADD_STAT(wrPerTurnAround, + "Writes before turning the bus around for reads"), + + ADD_STAT(bytesReadDRAM, "Total number of bytes read from DRAM"), + ADD_STAT(bytesReadWrQ, "Total number of bytes read from write queue"), + ADD_STAT(bytesWritten, "Total number of bytes written to DRAM"), + ADD_STAT(bytesReadSys, "Total read bytes from the system interface side"), + ADD_STAT(bytesWrittenSys, + "Total written bytes from the system interface side"), + + ADD_STAT(avgRdBW, "Average DRAM read bandwidth in MiByte/s"), + ADD_STAT(avgWrBW, "Average achieved write bandwidth in MiByte/s"), + ADD_STAT(avgRdBWSys, "Average system read bandwidth in MiByte/s"), + ADD_STAT(avgWrBWSys, "Average system write bandwidth in MiByte/s"), + ADD_STAT(peakBW, "Theoretical peak bandwidth in MiByte/s"), + + ADD_STAT(busUtil, "Data bus utilization in percentage"), + ADD_STAT(busUtilRead, "Data bus utilization in percentage for reads"), + ADD_STAT(busUtilWrite, "Data bus utilization in percentage for writes"), + + ADD_STAT(totGap, "Total gap between requests"), + ADD_STAT(avgGap, "Average gap between requests"), + + ADD_STAT(masterReadBytes, "Per-master bytes read from memory"), + ADD_STAT(masterWriteBytes, "Per-master bytes write to memory"), + ADD_STAT(masterReadRate, + "Per-master bytes read from memory rate (Bytes/sec)"), + ADD_STAT(masterWriteRate, + "Per-master bytes write to memory rate (Bytes/sec)"), + ADD_STAT(masterReadAccesses, + "Per-master read serviced memory accesses"), + ADD_STAT(masterWriteAccesses, + "Per-master write serviced memory accesses"), + ADD_STAT(masterReadTotalLat, + "Per-master read total memory access latency"), + ADD_STAT(masterWriteTotalLat, + "Per-master write total memory access latency"), + ADD_STAT(masterReadAvgLat, + "Per-master read average memory access latency"), + ADD_STAT(masterWriteAvgLat, + "Per-master write average memory access latency"), + + ADD_STAT(pageHitRate, "Row buffer hit rate, read and write combined") { - pwrStateTime - .init(6) - .name(name() + ".memoryStateTime") - .desc("Time in different power states"); - pwrStateTime.subname(0, "IDLE"); - pwrStateTime.subname(1, "REF"); - pwrStateTime.subname(2, "SREF"); - pwrStateTime.subname(3, "PRE_PDN"); - pwrStateTime.subname(4, "ACT"); - pwrStateTime.subname(5, "ACT_PDN"); - - actEnergy - .name(name() + ".actEnergy") - .desc("Energy for activate commands per rank (pJ)"); - - preEnergy - .name(name() + ".preEnergy") - .desc("Energy for precharge commands per rank (pJ)"); - - readEnergy - .name(name() + ".readEnergy") - .desc("Energy for read commands per rank (pJ)"); - - writeEnergy - .name(name() + ".writeEnergy") - .desc("Energy for write commands per rank (pJ)"); - - refreshEnergy - .name(name() + ".refreshEnergy") - .desc("Energy for refresh commands per rank (pJ)"); - - actBackEnergy - .name(name() + ".actBackEnergy") - .desc("Energy for active background per rank (pJ)"); - - preBackEnergy - .name(name() + ".preBackEnergy") - .desc("Energy for precharge background per rank (pJ)"); - - actPowerDownEnergy - .name(name() + ".actPowerDownEnergy") - .desc("Energy for active power-down per rank (pJ)"); - - prePowerDownEnergy - .name(name() + ".prePowerDownEnergy") - .desc("Energy for precharge power-down per rank (pJ)"); - - selfRefreshEnergy - .name(name() + ".selfRefreshEnergy") - .desc("Energy for self refresh per rank (pJ)"); - - totalEnergy - .name(name() + ".totalEnergy") - .desc("Total energy per rank (pJ)"); - - averagePower - .name(name() + ".averagePower") - .desc("Core power per rank (mW)"); - - totalIdleTime - .name(name() + ".totalIdleTime") - .desc("Total Idle time Per DRAM Rank"); - - Stats::registerDumpCallback(new RankDumpCallback(this)); - Stats::registerResetCallback(new RankResetCallback(this)); } + void -DRAMCtrl::regStats() +DRAMCtrl::DRAMStats::regStats() { using namespace Stats; - MemCtrl::regStats(); - - for (auto r : ranks) { - r->regStats(); - } - - registerResetCallback(new MemResetCallback(this)); - - readReqs - .name(name() + ".readReqs") - .desc("Number of read requests accepted"); - - writeReqs - .name(name() + ".writeReqs") - .desc("Number of write requests accepted"); - - readBursts - .name(name() + ".readBursts") - .desc("Number of DRAM read bursts, " - "including those serviced by the write queue"); - - writeBursts - .name(name() + ".writeBursts") - .desc("Number of DRAM write bursts, " - "including those merged in the write queue"); - - servicedByWrQ - .name(name() + ".servicedByWrQ") - .desc("Number of DRAM read bursts serviced by the write queue"); - - mergedWrBursts - .name(name() + ".mergedWrBursts") - .desc("Number of DRAM write bursts merged with an existing one"); - - neitherReadNorWrite - .name(name() + ".neitherReadNorWriteReqs") - .desc("Number of requests that are neither read nor write"); - - perBankRdBursts - .init(banksPerRank * ranksPerChannel) - .name(name() + ".perBankRdBursts") - .desc("Per bank write bursts"); - - perBankWrBursts - .init(banksPerRank * ranksPerChannel) - .name(name() + ".perBankWrBursts") - .desc("Per bank write bursts"); - - avgRdQLen - .name(name() + ".avgRdQLen") - .desc("Average read queue length when enqueuing") - .precision(2); - - avgWrQLen - .name(name() + ".avgWrQLen") - .desc("Average write queue length when enqueuing") - .precision(2); - - totQLat - .name(name() + ".totQLat") - .desc("Total ticks spent queuing"); - - totBusLat - .name(name() + ".totBusLat") - .desc("Total ticks spent in databus transfers"); - - totMemAccLat - .name(name() + ".totMemAccLat") - .desc("Total ticks spent from burst creation until serviced " - "by the DRAM"); - - avgQLat - .name(name() + ".avgQLat") - .desc("Average queueing delay per DRAM burst") - .precision(2); - - avgQLat = totQLat / (readBursts - servicedByWrQ); - - avgBusLat - .name(name() + ".avgBusLat") - .desc("Average bus latency per DRAM burst") - .precision(2); + System *sys = dram._system; + assert(sys); + const auto max_masters = dram._system->maxMasters(); - avgBusLat = totBusLat / (readBursts - servicedByWrQ); + perBankRdBursts.init(dram.banksPerRank * dram.ranksPerChannel); + perBankWrBursts.init(dram.banksPerRank * dram.ranksPerChannel); - avgMemAccLat - .name(name() + ".avgMemAccLat") - .desc("Average memory access latency per DRAM burst") - .precision(2); + avgRdQLen.precision(2); + avgWrQLen.precision(2); + avgQLat.precision(2); + avgBusLat.precision(2); + avgMemAccLat.precision(2); - avgMemAccLat = totMemAccLat / (readBursts - servicedByWrQ); + readRowHitRate.precision(2); + writeRowHitRate.precision(2); - numRdRetry - .name(name() + ".numRdRetry") - .desc("Number of times read queue was full causing retry"); + readPktSize.init(ceilLog2(dram.burstSize) + 1); + writePktSize.init(ceilLog2(dram.burstSize) + 1); - numWrRetry - .name(name() + ".numWrRetry") - .desc("Number of times write queue was full causing retry"); - - readRowHits - .name(name() + ".readRowHits") - .desc("Number of row buffer hits during reads"); - - writeRowHits - .name(name() + ".writeRowHits") - .desc("Number of row buffer hits during writes"); - - readRowHitRate - .name(name() + ".readRowHitRate") - .desc("Row buffer hit rate for reads") - .precision(2); + rdQLenPdf.init(dram.readBufferSize); + wrQLenPdf.init(dram.writeBufferSize); - readRowHitRate = (readRowHits / (readBursts - servicedByWrQ)) * 100; - - writeRowHitRate - .name(name() + ".writeRowHitRate") - .desc("Row buffer hit rate for writes") - .precision(2); - - writeRowHitRate = (writeRowHits / (writeBursts - mergedWrBursts)) * 100; - - readPktSize - .init(ceilLog2(burstSize) + 1) - .name(name() + ".readPktSize") - .desc("Read request sizes (log2)"); - - writePktSize - .init(ceilLog2(burstSize) + 1) - .name(name() + ".writePktSize") - .desc("Write request sizes (log2)"); - - rdQLenPdf - .init(readBufferSize) - .name(name() + ".rdQLenPdf") - .desc("What read queue length does an incoming req see"); - - wrQLenPdf - .init(writeBufferSize) - .name(name() + ".wrQLenPdf") - .desc("What write queue length does an incoming req see"); - - bytesPerActivate - .init(maxAccessesPerRow ? maxAccessesPerRow : rowBufferSize) - .name(name() + ".bytesPerActivate") - .desc("Bytes accessed per row activation") - .flags(nozero); - - rdPerTurnAround - .init(readBufferSize) - .name(name() + ".rdPerTurnAround") - .desc("Reads before turning the bus around for writes") - .flags(nozero); - - wrPerTurnAround - .init(writeBufferSize) - .name(name() + ".wrPerTurnAround") - .desc("Writes before turning the bus around for reads") - .flags(nozero); - - bytesReadDRAM - .name(name() + ".bytesReadDRAM") - .desc("Total number of bytes read from DRAM"); - - bytesReadWrQ - .name(name() + ".bytesReadWrQ") - .desc("Total number of bytes read from write queue"); - - bytesWritten - .name(name() + ".bytesWritten") - .desc("Total number of bytes written to DRAM"); - - bytesReadSys - .name(name() + ".bytesReadSys") - .desc("Total read bytes from the system interface side"); - - bytesWrittenSys - .name(name() + ".bytesWrittenSys") - .desc("Total written bytes from the system interface side"); - - avgRdBW - .name(name() + ".avgRdBW") - .desc("Average DRAM read bandwidth in MiByte/s") - .precision(2); - - avgRdBW = (bytesReadDRAM / 1000000) / simSeconds; - - avgWrBW - .name(name() + ".avgWrBW") - .desc("Average achieved write bandwidth in MiByte/s") - .precision(2); - - avgWrBW = (bytesWritten / 1000000) / simSeconds; - - avgRdBWSys - .name(name() + ".avgRdBWSys") - .desc("Average system read bandwidth in MiByte/s") - .precision(2); - - avgRdBWSys = (bytesReadSys / 1000000) / simSeconds; - - avgWrBWSys - .name(name() + ".avgWrBWSys") - .desc("Average system write bandwidth in MiByte/s") - .precision(2); - - avgWrBWSys = (bytesWrittenSys / 1000000) / simSeconds; - - peakBW - .name(name() + ".peakBW") - .desc("Theoretical peak bandwidth in MiByte/s") - .precision(2); - - peakBW = (SimClock::Frequency / tBURST) * burstSize / 1000000; - - busUtil - .name(name() + ".busUtil") - .desc("Data bus utilization in percentage") - .precision(2); - busUtil = (avgRdBW + avgWrBW) / peakBW * 100; - - totGap - .name(name() + ".totGap") - .desc("Total gap between requests"); - - avgGap - .name(name() + ".avgGap") - .desc("Average gap between requests") - .precision(2); - - avgGap = totGap / (readReqs + writeReqs); - - // Stats for DRAM Power calculation based on Micron datasheet - busUtilRead - .name(name() + ".busUtilRead") - .desc("Data bus utilization in percentage for reads") - .precision(2); - - busUtilRead = avgRdBW / peakBW * 100; - - busUtilWrite - .name(name() + ".busUtilWrite") - .desc("Data bus utilization in percentage for writes") - .precision(2); + bytesPerActivate + .init(dram.maxAccessesPerRow ? + dram.maxAccessesPerRow : dram.rowBufferSize) + .flags(nozero); - busUtilWrite = avgWrBW / peakBW * 100; + rdPerTurnAround + .init(dram.readBufferSize) + .flags(nozero); + wrPerTurnAround + .init(dram.writeBufferSize) + .flags(nozero); - pageHitRate - .name(name() + ".pageHitRate") - .desc("Row buffer hit rate, read and write combined") - .precision(2); + avgRdBW.precision(2); + avgWrBW.precision(2); + avgRdBWSys.precision(2); + avgWrBWSys.precision(2); + peakBW.precision(2); + busUtil.precision(2); + avgGap.precision(2); + busUtilWrite.precision(2); + pageHitRate.precision(2); - pageHitRate = (writeRowHits + readRowHits) / - (writeBursts - mergedWrBursts + readBursts - servicedByWrQ) * 100; // per-master bytes read and written to memory masterReadBytes - .init(_system->maxMasters()) - .name(name() + ".masterReadBytes") - .desc("Per-master bytes read from memory") + .init(max_masters) .flags(nozero | nonan); masterWriteBytes - .init(_system->maxMasters()) - .name(name() + ".masterWriteBytes") - .desc("Per-master bytes write to memory") + .init(max_masters) .flags(nozero | nonan); // per-master bytes read and written to memory rate - masterReadRate.name(name() + ".masterReadRate") - .desc("Per-master bytes read from memory rate (Bytes/sec)") + masterReadRate .flags(nozero | nonan) .precision(12); - masterReadRate = masterReadBytes/simSeconds; - - masterWriteRate - .name(name() + ".masterWriteRate") - .desc("Per-master bytes write to memory rate (Bytes/sec)") - .flags(nozero | nonan) - .precision(12); - - masterWriteRate = masterWriteBytes/simSeconds; - masterReadAccesses - .init(_system->maxMasters()) - .name(name() + ".masterReadAccesses") - .desc("Per-master read serviced memory accesses") + .init(max_masters) .flags(nozero); masterWriteAccesses - .init(_system->maxMasters()) - .name(name() + ".masterWriteAccesses") - .desc("Per-master write serviced memory accesses") + .init(max_masters) .flags(nozero); - masterReadTotalLat - .init(_system->maxMasters()) - .name(name() + ".masterReadTotalLat") - .desc("Per-master read total memory access latency") + .init(max_masters) .flags(nozero | nonan); - masterReadAvgLat.name(name() + ".masterReadAvgLat") - .desc("Per-master read average memory access latency") + masterReadAvgLat .flags(nonan) .precision(2); - masterReadAvgLat = masterReadTotalLat/masterReadAccesses; + + busUtilRead + .precision(2); + + masterWriteRate + .flags(nozero | nonan) + .precision(12); masterWriteTotalLat - .init(_system->maxMasters()) - .name(name() + ".masterWriteTotalLat") - .desc("Per-master write total memory access latency") + .init(max_masters) .flags(nozero | nonan); - masterWriteAvgLat.name(name() + ".masterWriteAvgLat") - .desc("Per-master write average memory access latency") + masterWriteAvgLat .flags(nonan) .precision(2); - masterWriteAvgLat = masterWriteTotalLat/masterWriteAccesses; - - for (int i = 0; i < _system->maxMasters(); i++) { - const std::string master = _system->getMasterName(i); + for (int i = 0; i < max_masters; i++) { + const std::string master = dram._system->getMasterName(i); masterReadBytes.subname(i, master); masterReadRate.subname(i, master); masterWriteBytes.subname(i, master); @@ -2838,6 +2639,96 @@ DRAMCtrl::regStats() masterWriteTotalLat.subname(i, master); masterWriteAvgLat.subname(i, master); } + + // Formula stats + avgQLat = totQLat / (readBursts - servicedByWrQ); + avgBusLat = totBusLat / (readBursts - servicedByWrQ); + avgMemAccLat = totMemAccLat / (readBursts - servicedByWrQ); + + readRowHitRate = (readRowHits / (readBursts - servicedByWrQ)) * 100; + writeRowHitRate = (writeRowHits / (writeBursts - mergedWrBursts)) * 100; + + avgRdBW = (bytesReadDRAM / 1000000) / simSeconds; + avgWrBW = (bytesWritten / 1000000) / simSeconds; + avgRdBWSys = (bytesReadSys / 1000000) / simSeconds; + avgWrBWSys = (bytesWrittenSys / 1000000) / simSeconds; + peakBW = (SimClock::Frequency / dram.tBURST) * dram.burstSize / 1000000; + + busUtil = (avgRdBW + avgWrBW) / peakBW * 100; + + avgGap = totGap / (readReqs + writeReqs); + + busUtilRead = avgRdBW / peakBW * 100; + busUtilWrite = avgWrBW / peakBW * 100; + + pageHitRate = (writeRowHits + readRowHits) / + (writeBursts - mergedWrBursts + readBursts - servicedByWrQ) * 100; + + masterReadRate = masterReadBytes / simSeconds; + masterWriteRate = masterWriteBytes / simSeconds; + masterReadAvgLat = masterReadTotalLat / masterReadAccesses; + masterWriteAvgLat = masterWriteTotalLat / masterWriteAccesses; +} + +void +DRAMCtrl::DRAMStats::resetStats() +{ + dram.lastStatsResetTick = curTick(); +} + +DRAMCtrl::RankStats::RankStats(DRAMCtrl &_memory, Rank &_rank) + : Stats::Group(&_memory, csprintf("rank%d", _rank.rank).c_str()), + rank(_rank), + + ADD_STAT(actEnergy, "Energy for activate commands per rank (pJ)"), + ADD_STAT(preEnergy, "Energy for precharge commands per rank (pJ)"), + ADD_STAT(readEnergy, "Energy for read commands per rank (pJ)"), + ADD_STAT(writeEnergy, "Energy for write commands per rank (pJ)"), + ADD_STAT(refreshEnergy, "Energy for refresh commands per rank (pJ)"), + ADD_STAT(actBackEnergy, "Energy for active background per rank (pJ)"), + ADD_STAT(preBackEnergy, "Energy for precharge background per rank (pJ)"), + ADD_STAT(actPowerDownEnergy, + "Energy for active power-down per rank (pJ)"), + ADD_STAT(prePowerDownEnergy, + "Energy for precharge power-down per rank (pJ)"), + ADD_STAT(selfRefreshEnergy, "Energy for self refresh per rank (pJ)"), + + ADD_STAT(totalEnergy, "Total energy per rank (pJ)"), + ADD_STAT(averagePower, "Core power per rank (mW)"), + + ADD_STAT(totalIdleTime, "Total Idle time Per DRAM Rank"), + ADD_STAT(memoryStateTime, "Time in different power states") +{ +} + +void +DRAMCtrl::RankStats::regStats() +{ + Stats::Group::regStats(); + + memoryStateTime.init(6); + memoryStateTime.subname(0, "IDLE"); + memoryStateTime.subname(1, "REF"); + memoryStateTime.subname(2, "SREF"); + memoryStateTime.subname(3, "PRE_PDN"); + memoryStateTime.subname(4, "ACT"); + memoryStateTime.subname(5, "ACT_PDN"); +} + +void +DRAMCtrl::RankStats::resetStats() +{ + Stats::Group::resetStats(); + + rank.resetStats(); +} + +void +DRAMCtrl::RankStats::preDumpStats() +{ + Stats::Group::preDumpStats(); + + rank.computeStats(); } void diff --git a/src/mem/dram_ctrl.hh b/src/mem/dram_ctrl.hh index 7de0872ea..8c8c24552 100644 --- a/src/mem/dram_ctrl.hh +++ b/src/mem/dram_ctrl.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018 ARM Limited + * Copyright (c) 2012-2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -270,43 +270,16 @@ class DRAMCtrl : public QoS::MemCtrl REF_RUN }; - /** - * Rank class includes a vector of banks. Refresh and Power state - * machines are defined per rank. Events required to change the - * state of the refresh and power state machine are scheduled per - * rank. This class allows the implementation of rank-wise refresh - * and rank-wise power-down. - */ - class Rank : public EventManager + class Rank; + struct RankStats : public Stats::Group { + RankStats(DRAMCtrl& memory, Rank &rank); - private: - - /** - * A reference to the parent DRAMCtrl instance - */ - DRAMCtrl& memory; - - /** - * Since we are taking decisions out of order, we need to keep - * track of what power transition is happening at what time - */ - PowerState pwrStateTrans; - - /** - * Previous low-power state, which will be re-entered after refresh. - */ - PowerState pwrStatePostRefresh; - - /** - * Track when we transitioned to the current power state - */ - Tick pwrStateTick; + void regStats() override; + void resetStats() override; + void preDumpStats() override; - /** - * Keep track of when a refresh is due. - */ - Tick refreshDueAt; + Rank &rank; /* * Command energies @@ -354,7 +327,46 @@ class DRAMCtrl : public QoS::MemCtrl /** * Track time spent in each power state. */ - Stats::Vector pwrStateTime; + Stats::Vector memoryStateTime; + }; + + /** + * Rank class includes a vector of banks. Refresh and Power state + * machines are defined per rank. Events required to change the + * state of the refresh and power state machine are scheduled per + * rank. This class allows the implementation of rank-wise refresh + * and rank-wise power-down. + */ + class Rank : public EventManager + { + + private: + + /** + * A reference to the parent DRAMCtrl instance + */ + DRAMCtrl& memory; + + /** + * Since we are taking decisions out of order, we need to keep + * track of what power transition is happening at what time + */ + PowerState pwrStateTrans; + + /** + * Previous low-power state, which will be re-entered after refresh. + */ + PowerState pwrStatePostRefresh; + + /** + * Track when we transitioned to the current power state + */ + Tick pwrStateTick; + + /** + * Keep track of when a refresh is due. + */ + Tick refreshDueAt; /** * Function to update Power Stats @@ -566,44 +578,8 @@ class DRAMCtrl : public QoS::MemCtrl void processWakeUpEvent(); EventFunctionWrapper wakeUpEvent; - }; - - /** - * 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; - public: - RankDumpCallback(Rank *r) : ranks(r) {} - 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(); }; + protected: + RankStats stats; }; /** @@ -1051,85 +1027,101 @@ class DRAMCtrl : public QoS::MemCtrl */ Tick nextReqTime; - // All statistics that the model needs to capture - Stats::Scalar readReqs; - Stats::Scalar writeReqs; - Stats::Scalar readBursts; - Stats::Scalar writeBursts; - Stats::Scalar bytesReadDRAM; - Stats::Scalar bytesReadWrQ; - Stats::Scalar bytesWritten; - Stats::Scalar bytesReadSys; - Stats::Scalar bytesWrittenSys; - Stats::Scalar servicedByWrQ; - Stats::Scalar mergedWrBursts; - Stats::Scalar neitherReadNorWrite; - Stats::Vector perBankRdBursts; - Stats::Vector perBankWrBursts; - Stats::Scalar numRdRetry; - Stats::Scalar numWrRetry; - Stats::Scalar totGap; - Stats::Vector readPktSize; - Stats::Vector writePktSize; - Stats::Vector rdQLenPdf; - Stats::Vector wrQLenPdf; - Stats::Histogram bytesPerActivate; - Stats::Histogram rdPerTurnAround; - Stats::Histogram wrPerTurnAround; - - // per-master bytes read and written to memory - Stats::Vector masterReadBytes; - Stats::Vector masterWriteBytes; - - // per-master bytes read and written to memory rate - Stats::Formula masterReadRate; - Stats::Formula masterWriteRate; - - // per-master read and write serviced memory accesses - Stats::Vector masterReadAccesses; - Stats::Vector masterWriteAccesses; - - // per-master read and write total memory access latency - Stats::Vector masterReadTotalLat; - Stats::Vector masterWriteTotalLat; - - // per-master raed and write average memory access latency - Stats::Formula masterReadAvgLat; - Stats::Formula masterWriteAvgLat; - - // Latencies summed over all requests - Stats::Scalar totQLat; - Stats::Scalar totMemAccLat; - Stats::Scalar totBusLat; - - // Average latencies per request - Stats::Formula avgQLat; - Stats::Formula avgBusLat; - Stats::Formula avgMemAccLat; - - // Average bandwidth - Stats::Formula avgRdBW; - Stats::Formula avgWrBW; - Stats::Formula avgRdBWSys; - Stats::Formula avgWrBWSys; - Stats::Formula peakBW; - Stats::Formula busUtil; - Stats::Formula busUtilRead; - Stats::Formula busUtilWrite; - - // Average queue lengths - Stats::Average avgRdQLen; - Stats::Average avgWrQLen; - - // Row hit count and rate - Stats::Scalar readRowHits; - Stats::Scalar writeRowHits; - Stats::Formula readRowHitRate; - Stats::Formula writeRowHitRate; - Stats::Formula avgGap; - - // DRAM Power Calculation - Stats::Formula pageHitRate; + /** All statistics that the model needs to capture */ + struct DRAMStats : public Stats::Group { + DRAMStats(DRAMCtrl &dram); + + void regStats() override; + void resetStats() override; + + DRAMCtrl &dram; + + Stats::Scalar readReqs; + Stats::Scalar writeReqs; + Stats::Scalar readBursts; + Stats::Scalar writeBursts; + Stats::Scalar servicedByWrQ; + Stats::Scalar mergedWrBursts; + Stats::Scalar neitherReadNorWriteReqs; + Stats::Vector perBankRdBursts; + Stats::Vector perBankWrBursts; + + // Average queue lengths + Stats::Average avgRdQLen; + Stats::Average avgWrQLen; + + // Latencies summed over all requests + Stats::Scalar totQLat; + Stats::Scalar totBusLat; + Stats::Scalar totMemAccLat; + + // Average latencies per request + Stats::Formula avgQLat; + Stats::Formula avgBusLat; + Stats::Formula avgMemAccLat; + + Stats::Scalar numRdRetry; + Stats::Scalar numWrRetry; + + // Row hit count and rate + Stats::Scalar readRowHits; + Stats::Scalar writeRowHits; + Stats::Formula readRowHitRate; + Stats::Formula writeRowHitRate; + + Stats::Vector readPktSize; + Stats::Vector writePktSize; + Stats::Vector rdQLenPdf; + Stats::Vector wrQLenPdf; + Stats::Histogram bytesPerActivate; + Stats::Histogram rdPerTurnAround; + Stats::Histogram wrPerTurnAround; + + Stats::Scalar bytesReadDRAM; + Stats::Scalar bytesReadWrQ; + Stats::Scalar bytesWritten; + Stats::Scalar bytesReadSys; + Stats::Scalar bytesWrittenSys; + + // Average bandwidth + Stats::Formula avgRdBW; + Stats::Formula avgWrBW; + Stats::Formula avgRdBWSys; + Stats::Formula avgWrBWSys; + Stats::Formula peakBW; + + Stats::Formula busUtil; + Stats::Formula busUtilRead; + Stats::Formula busUtilWrite; + + Stats::Scalar totGap; + Stats::Formula avgGap; + + // per-master bytes read and written to memory + Stats::Vector masterReadBytes; + Stats::Vector masterWriteBytes; + + // per-master bytes read and written to memory rate + Stats::Formula masterReadRate; + Stats::Formula masterWriteRate; + + // per-master read and write serviced memory accesses + Stats::Vector masterReadAccesses; + Stats::Vector masterWriteAccesses; + + // per-master read and write total memory access latency + Stats::Vector masterReadTotalLat; + Stats::Vector masterWriteTotalLat; + + // per-master raed and write average memory access latency + Stats::Formula masterReadAvgLat; + Stats::Formula masterWriteAvgLat; + + // DRAM Power Calculation + Stats::Formula pageHitRate; + }; + + DRAMStats stats; // Holds the value of the rank of burst issued uint8_t activeRank; @@ -1172,9 +1164,6 @@ class DRAMCtrl : public QoS::MemCtrl }; public: - - void regStats() override; - DRAMCtrl(const DRAMCtrlParams* p); DrainState drain() override; diff --git a/src/mem/qos/mem_ctrl.cc b/src/mem/qos/mem_ctrl.cc index 27ff0eb61..5ced58ae8 100644 --- a/src/mem/qos/mem_ctrl.cc +++ b/src/mem/qos/mem_ctrl.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited + * Copyright (c) 2017-2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -52,7 +52,8 @@ MemCtrl::MemCtrl(const QoSMemCtrlParams * p) qosPriorityEscalation(p->qos_priority_escalation), qosSyncroScheduler(p->qos_syncro_scheduler), totalReadQueueSize(0), totalWriteQueueSize(0), - busState(READ), busStateNext(READ) + busState(READ), busStateNext(READ), + stats(*this) { // Set the priority policy if (policy) { @@ -113,7 +114,7 @@ MemCtrl::logRequest(BusState dir, MasterID m_id, uint8_t qos, } // Record statistics - avgPriority[m_id].sample(qos); + stats.avgPriority[m_id].sample(qos); // Compute avg priority distance @@ -122,7 +123,7 @@ MemCtrl::logRequest(BusState dir, MasterID m_id, uint8_t qos, (abs(int(qos) - int(i))) * packetPriorities[m_id][i]; if (distance > 0) { - avgPriorityDistance[m_id].sample(distance); + stats.avgPriorityDistance[m_id].sample(distance); DPRINTF(QOS, "QoSMemCtrl::logRequest MASTER %s [id %d]" " registering priority distance %d for priority %d" @@ -191,13 +192,13 @@ MemCtrl::logResponse(BusState dir, MasterID m_id, uint8_t qos, if (latency > 0) { // Record per-priority latency stats - if (priorityMaxLatency[qos].value() < latency) { - priorityMaxLatency[qos] = latency; + if (stats.priorityMaxLatency[qos].value() < latency) { + stats.priorityMaxLatency[qos] = latency; } - if (priorityMinLatency[qos].value() > latency - || priorityMinLatency[qos].value() == 0) { - priorityMinLatency[qos] = latency; + if (stats.priorityMinLatency[qos].value() > latency + || stats.priorityMinLatency[qos].value() == 0) { + stats.priorityMinLatency[qos] = latency; } } } @@ -280,52 +281,71 @@ MemCtrl::addMaster(MasterID m_id) } } +MemCtrl::MemCtrlStats::MemCtrlStats(MemCtrl &mc) + : Stats::Group(&mc), + memCtrl(mc), + + ADD_STAT(avgPriority, + "Average QoS priority value for accepted requests"), + ADD_STAT(avgPriorityDistance, + "Average QoS priority distance between assigned and " + "queued values"), + + ADD_STAT(priorityMinLatency, + "per QoS priority minimum request to response latency (s)"), + ADD_STAT(priorityMaxLatency, + "per QoS priority maximum request to response latency (s)"), + ADD_STAT(numReadWriteTurnArounds, + "Number of turnarounds from READ to WRITE"), + ADD_STAT(numWriteReadTurnArounds, + "Number of turnarounds from WRITE to READ"), + ADD_STAT(numStayReadState, + "Number of times bus staying in READ state"), + ADD_STAT(numStayWriteState, + "Number of times bus staying in WRITE state") +{ +} + void -MemCtrl::regStats() +MemCtrl::MemCtrlStats::regStats() { - AbstractMemory::regStats(); + Stats::Group::regStats(); using namespace Stats; - // Initializes per master statistics - avgPriority.init(_system->maxMasters()).name(name() + ".avgPriority") - .desc("Average QoS priority value for accepted requests") - .flags(nozero | nonan).precision(2); - - avgPriorityDistance.init(_system->maxMasters()) - .name(name() + ".avgPriorityDistance") - .desc("Average QoS priority distance between assigned and " - "queued values").flags(nozero | nonan); - - priorityMinLatency.init(numPriorities()) - .name(name() + ".priorityMinLatency") - .desc("per QoS priority minimum request to response latency (s)") - .precision(12); + System *system = memCtrl._system; + const auto max_masters = system->maxMasters(); + const auto num_priorities = memCtrl.numPriorities(); - priorityMaxLatency.init(numPriorities()) - .name(name() + ".priorityMaxLatency") - .desc("per QoS priority maximum request to response latency (s)") - .precision(12); - - numReadWriteTurnArounds.name(name() + ".numReadWriteTurnArounds") - .desc("Number of turnarounds from READ to WRITE"); - - numWriteReadTurnArounds.name(name() + ".numWriteReadTurnArounds") - .desc("Number of turnarounds from WRITE to READ"); - - numStayReadState.name(name() + ".numStayReadState") - .desc("Number of times bus staying in READ state"); - - numStayWriteState.name(name() + ".numStayWriteState") - .desc("Number of times bus staying in WRITE state"); - - for (int i = 0; i < _system->maxMasters(); i++) { - const std::string master = _system->getMasterName(i); + // Initializes per master statistics + avgPriority + .init(max_masters) + .flags(nozero | nonan) + .precision(2) + ; + + avgPriorityDistance + .init(max_masters) + .flags(nozero | nonan) + ; + + priorityMinLatency + .init(num_priorities) + .precision(12) + ; + + priorityMaxLatency + .init(num_priorities) + .precision(12) + ; + + for (int i = 0; i < max_masters; i++) { + const std::string master = system->getMasterName(i); avgPriority.subname(i, master); avgPriorityDistance.subname(i, master); } - for (int j = 0; j < numPriorities(); ++j) { + for (int j = 0; j < num_priorities; ++j) { priorityMinLatency.subname(j, std::to_string(j)); priorityMaxLatency.subname(j, std::to_string(j)); } @@ -336,15 +356,15 @@ MemCtrl::recordTurnaroundStats() { if (busStateNext != busState) { if (busState == READ) { - numWriteReadTurnArounds++; + stats.numWriteReadTurnArounds++; } else if (busState == WRITE) { - numReadWriteTurnArounds++; + stats.numReadWriteTurnArounds++; } } else { if (busState == READ) { - numStayReadState++; + stats.numStayReadState++; } else if (busState == WRITE) { - numStayWriteState++; + stats.numStayWriteState++; } } } diff --git a/src/mem/qos/mem_ctrl.hh b/src/mem/qos/mem_ctrl.hh index db85f276d..e31f21b23 100644 --- a/src/mem/qos/mem_ctrl.hh +++ b/src/mem/qos/mem_ctrl.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 ARM Limited + * Copyright (c) 2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -123,26 +123,35 @@ class MemCtrl: public AbstractMemory /** bus state for next request event triggered */ BusState busStateNext; - /** per-master average QoS priority */ - Stats::VectorStandardDeviation avgPriority; - /** per-master average QoS distance between assigned and queued values */ - Stats::VectorStandardDeviation avgPriorityDistance; - - /** per-priority minimum latency */ - Stats::Vector priorityMinLatency; - /** per-priority maximum latency */ - Stats::Vector priorityMaxLatency; - /** Count the number of turnarounds READ to WRITE */ - Stats::Scalar numReadWriteTurnArounds; - /** Count the number of turnarounds WRITE to READ */ - Stats::Scalar numWriteReadTurnArounds; - /** Count the number of times bus staying in READ state */ - Stats::Scalar numStayReadState; - /** Count the number of times bus staying in WRITE state */ - Stats::Scalar numStayWriteState; - - /** registers statistics */ - void regStats() override; + struct MemCtrlStats : public Stats::Group + { + MemCtrlStats(MemCtrl &mc); + + void regStats() override; + + const MemCtrl &memCtrl; + + /** per-master average QoS priority */ + Stats::VectorStandardDeviation avgPriority; + /** + * per-master average QoS distance between assigned and + * queued values + */ + Stats::VectorStandardDeviation avgPriorityDistance; + + /** per-priority minimum latency */ + Stats::Vector priorityMinLatency; + /** per-priority maximum latency */ + Stats::Vector priorityMaxLatency; + /** Count the number of turnarounds READ to WRITE */ + Stats::Scalar numReadWriteTurnArounds; + /** Count the number of turnarounds WRITE to READ */ + Stats::Scalar numWriteReadTurnArounds; + /** Count the number of times bus staying in READ state */ + Stats::Scalar numStayReadState; + /** Count the number of times bus staying in WRITE state */ + Stats::Scalar numStayWriteState; + } stats; /** * Initializes dynamically counters and -- 2.30.2