summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mem/abstract_mem.cc131
-rw-r--r--src/mem/abstract_mem.hh56
-rw-r--r--src/mem/dram_ctrl.cc711
-rw-r--r--src/mem/dram_ctrl.hh301
-rw-r--r--src/mem/qos/mem_ctrl.cc118
-rw-r--r--src/mem/qos/mem_ctrl.hh51
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