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:
@@ -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());
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user