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 <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21142
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
Reviewed-by: Wendy Elsasser <wendy.elsasser@arm.com>
This commit is contained in:
Andreas Sandberg
2019-09-23 18:20:23 +01:00
parent a060ac8630
commit 76384ec3ff
6 changed files with 632 additions and 704 deletions

View File

@@ -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());

View File

@@ -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__

View File

@@ -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();
System *sys = dram._system;
assert(sys);
const auto max_masters = dram._system->maxMasters();
for (auto r : ranks) {
r->regStats();
}
perBankRdBursts.init(dram.banksPerRank * dram.ranksPerChannel);
perBankWrBursts.init(dram.banksPerRank * dram.ranksPerChannel);
registerResetCallback(new MemResetCallback(this));
avgRdQLen.precision(2);
avgWrQLen.precision(2);
avgQLat.precision(2);
avgBusLat.precision(2);
avgMemAccLat.precision(2);
readReqs
.name(name() + ".readReqs")
.desc("Number of read requests accepted");
readRowHitRate.precision(2);
writeRowHitRate.precision(2);
writeReqs
.name(name() + ".writeReqs")
.desc("Number of write requests accepted");
readPktSize.init(ceilLog2(dram.burstSize) + 1);
writePktSize.init(ceilLog2(dram.burstSize) + 1);
readBursts
.name(name() + ".readBursts")
.desc("Number of DRAM read bursts, "
"including those serviced by the write queue");
rdQLenPdf.init(dram.readBufferSize);
wrQLenPdf.init(dram.writeBufferSize);
writeBursts
.name(name() + ".writeBursts")
.desc("Number of DRAM write bursts, "
"including those merged in the write queue");
bytesPerActivate
.init(dram.maxAccessesPerRow ?
dram.maxAccessesPerRow : dram.rowBufferSize)
.flags(nozero);
servicedByWrQ
.name(name() + ".servicedByWrQ")
.desc("Number of DRAM read bursts serviced by the write queue");
rdPerTurnAround
.init(dram.readBufferSize)
.flags(nozero);
wrPerTurnAround
.init(dram.writeBufferSize)
.flags(nozero);
mergedWrBursts
.name(name() + ".mergedWrBursts")
.desc("Number of DRAM write bursts merged with an existing one");
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);
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);
avgBusLat = totBusLat / (readBursts - servicedByWrQ);
avgMemAccLat
.name(name() + ".avgMemAccLat")
.desc("Average memory access latency per DRAM burst")
.precision(2);
avgMemAccLat = totMemAccLat / (readBursts - servicedByWrQ);
numRdRetry
.name(name() + ".numRdRetry")
.desc("Number of times read queue was full causing retry");
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);
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);
busUtilWrite = avgWrBW / peakBW * 100;
pageHitRate
.name(name() + ".pageHitRate")
.desc("Row buffer hit rate, read and write combined")
.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

View File

@@ -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:
void regStats() override;
void resetStats() override;
void preDumpStats() override;
/**
* 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;
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;
/** All statistics that the model needs to capture */
struct DRAMStats : public Stats::Group {
DRAMStats(DRAMCtrl &dram);
// per-master bytes read and written to memory
Stats::Vector masterReadBytes;
Stats::Vector masterWriteBytes;
void regStats() override;
void resetStats() override;
// per-master bytes read and written to memory rate
Stats::Formula masterReadRate;
Stats::Formula masterWriteRate;
DRAMCtrl &dram;
// per-master read and write serviced memory accesses
Stats::Vector masterReadAccesses;
Stats::Vector masterWriteAccesses;
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;
// per-master read and write total memory access latency
Stats::Vector masterReadTotalLat;
Stats::Vector masterWriteTotalLat;
// Average queue lengths
Stats::Average avgRdQLen;
Stats::Average avgWrQLen;
// 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 totBusLat;
Stats::Scalar totMemAccLat;
// 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 latencies per request
Stats::Formula avgQLat;
Stats::Formula avgBusLat;
Stats::Formula avgMemAccLat;
Stats::Scalar numRdRetry;
Stats::Scalar numWrRetry;
// 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;
// Row hit count and rate
Stats::Scalar readRowHits;
Stats::Scalar writeRowHits;
Stats::Formula readRowHitRate;
Stats::Formula writeRowHitRate;
// Average queue lengths
Stats::Average avgRdQLen;
Stats::Average avgWrQLen;
Stats::Vector readPktSize;
Stats::Vector writePktSize;
Stats::Vector rdQLenPdf;
Stats::Vector wrQLenPdf;
Stats::Histogram bytesPerActivate;
Stats::Histogram rdPerTurnAround;
Stats::Histogram wrPerTurnAround;
// Row hit count and rate
Stats::Scalar readRowHits;
Stats::Scalar writeRowHits;
Stats::Formula readRowHitRate;
Stats::Formula writeRowHitRate;
Stats::Formula avgGap;
Stats::Scalar bytesReadDRAM;
Stats::Scalar bytesReadWrQ;
Stats::Scalar bytesWritten;
Stats::Scalar bytesReadSys;
Stats::Scalar bytesWrittenSys;
// DRAM Power Calculation
Stats::Formula pageHitRate;
// 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;

View File

@@ -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)
}
}
void
MemCtrl::regStats()
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")
{
AbstractMemory::regStats();
}
void
MemCtrl::MemCtrlStats::regStats()
{
Stats::Group::regStats();
using namespace Stats;
System *system = memCtrl._system;
const auto max_masters = system->maxMasters();
const auto num_priorities = memCtrl.numPriorities();
// Initializes per master statistics
avgPriority.init(_system->maxMasters()).name(name() + ".avgPriority")
.desc("Average QoS priority value for accepted requests")
.flags(nozero | nonan).precision(2);
avgPriority
.init(max_masters)
.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);
avgPriorityDistance
.init(max_masters)
.flags(nozero | nonan)
;
priorityMinLatency.init(numPriorities())
.name(name() + ".priorityMinLatency")
.desc("per QoS priority minimum request to response latency (s)")
.precision(12);
priorityMinLatency
.init(num_priorities)
.precision(12)
;
priorityMaxLatency.init(numPriorities())
.name(name() + ".priorityMaxLatency")
.desc("per QoS priority maximum request to response latency (s)")
.precision(12);
priorityMaxLatency
.init(num_priorities)
.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);
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++;
}
}
}

View File

@@ -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;
struct MemCtrlStats : public Stats::Group
{
MemCtrlStats(MemCtrl &mc);
/** 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;
void regStats() override;
/** registers statistics */
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