mem: Fixes for DRAM stats accounting
This patch fixes a number of stats accounting issues in the DRAM controller. Most importantly, it separates the system interface and DRAM interface so that it is clearer what the actual DRAM bandwidth (and consequently utilisation) is.
This commit is contained in:
parent
ce93982cc6
commit
460cc77d6d
2 changed files with 84 additions and 86 deletions
|
@ -329,7 +329,6 @@ SimpleDRAM::addToReadQueue(PacketPtr pkt, unsigned int pktCount)
|
||||||
DPRINTF(DRAM, "Read to addr %lld with size %d serviced by "
|
DPRINTF(DRAM, "Read to addr %lld with size %d serviced by "
|
||||||
"write queue\n", addr, size);
|
"write queue\n", addr, size);
|
||||||
bytesReadWrQ += burstSize;
|
bytesReadWrQ += burstSize;
|
||||||
bytesConsumedRd += size;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,9 +355,6 @@ SimpleDRAM::addToReadQueue(PacketPtr pkt, unsigned int pktCount)
|
||||||
readQueue.push_back(dram_pkt);
|
readQueue.push_back(dram_pkt);
|
||||||
|
|
||||||
// Update stats
|
// Update stats
|
||||||
assert(dram_pkt->bankId < ranksPerChannel * banksPerRank);
|
|
||||||
perBankRdReqs[dram_pkt->bankId]++;
|
|
||||||
|
|
||||||
avgRdQLen = readQueue.size() + respQueue.size();
|
avgRdQLen = readQueue.size() + respQueue.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,15 +547,13 @@ SimpleDRAM::addToWriteQueue(PacketPtr pkt, unsigned int pktCount)
|
||||||
writeQueue.push_back(dram_pkt);
|
writeQueue.push_back(dram_pkt);
|
||||||
|
|
||||||
// Update stats
|
// Update stats
|
||||||
assert(dram_pkt->bankId < ranksPerChannel * banksPerRank);
|
|
||||||
perBankWrReqs[dram_pkt->bankId]++;
|
|
||||||
|
|
||||||
avgWrQLen = writeQueue.size();
|
avgWrQLen = writeQueue.size();
|
||||||
|
} else {
|
||||||
|
// keep track of the fact that this burst effectively
|
||||||
|
// disappeared as it was merged with an existing one
|
||||||
|
mergedWrBursts++;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesConsumedWr += size;
|
|
||||||
bytesWritten += burstSize;
|
|
||||||
|
|
||||||
// Starting address of next dram pkt (aligend to burstSize boundary)
|
// Starting address of next dram pkt (aligend to burstSize boundary)
|
||||||
addr = (addr | (burstSize - 1)) + 1;
|
addr = (addr | (burstSize - 1)) + 1;
|
||||||
}
|
}
|
||||||
|
@ -694,6 +688,7 @@ SimpleDRAM::recvTimingReq(PacketPtr pkt)
|
||||||
addToReadQueue(pkt, dram_pkt_count);
|
addToReadQueue(pkt, dram_pkt_count);
|
||||||
readReqs++;
|
readReqs++;
|
||||||
numReqs++;
|
numReqs++;
|
||||||
|
bytesReadSys += size;
|
||||||
}
|
}
|
||||||
} else if (pkt->isWrite()) {
|
} else if (pkt->isWrite()) {
|
||||||
assert(size != 0);
|
assert(size != 0);
|
||||||
|
@ -707,6 +702,7 @@ SimpleDRAM::recvTimingReq(PacketPtr pkt)
|
||||||
addToWriteQueue(pkt, dram_pkt_count);
|
addToWriteQueue(pkt, dram_pkt_count);
|
||||||
writeReqs++;
|
writeReqs++;
|
||||||
numReqs++;
|
numReqs++;
|
||||||
|
bytesWrittenSys += size;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DPRINTF(DRAM,"Neither read nor write, ignore timing\n");
|
DPRINTF(DRAM,"Neither read nor write, ignore timing\n");
|
||||||
|
@ -727,9 +723,6 @@ SimpleDRAM::processRespondEvent()
|
||||||
|
|
||||||
DRAMPacket* dram_pkt = respQueue.front();
|
DRAMPacket* dram_pkt = respQueue.front();
|
||||||
|
|
||||||
// Actually responds to the requestor
|
|
||||||
bytesConsumedRd += dram_pkt->size;
|
|
||||||
bytesReadDRAM += burstSize;
|
|
||||||
if (dram_pkt->burstHelper) {
|
if (dram_pkt->burstHelper) {
|
||||||
// it is a split packet
|
// it is a split packet
|
||||||
dram_pkt->burstHelper->burstsServiced++;
|
dram_pkt->burstHelper->burstsServiced++;
|
||||||
|
@ -1172,28 +1165,29 @@ SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt)
|
||||||
DPRINTF(DRAM,"Access time is %lld\n",
|
DPRINTF(DRAM,"Access time is %lld\n",
|
||||||
dram_pkt->readyTime - dram_pkt->entryTime);
|
dram_pkt->readyTime - dram_pkt->entryTime);
|
||||||
|
|
||||||
if (rowHitFlag) {
|
|
||||||
if(dram_pkt->isRead)
|
|
||||||
readRowHits++;
|
|
||||||
else
|
|
||||||
writeRowHits++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the minimum timing between the requests
|
// Update the minimum timing between the requests
|
||||||
newTime = (busBusyUntil > tRP + tRCD + tCL) ?
|
newTime = (busBusyUntil > tRP + tRCD + tCL) ?
|
||||||
std::max(busBusyUntil - (tRP + tRCD + tCL), curTick()) : curTick();
|
std::max(busBusyUntil - (tRP + tRCD + tCL), curTick()) : curTick();
|
||||||
|
|
||||||
|
// Update the access related stats
|
||||||
|
if (dram_pkt->isRead) {
|
||||||
|
if (rowHitFlag)
|
||||||
|
readRowHits++;
|
||||||
|
bytesReadDRAM += burstSize;
|
||||||
|
perBankRdBursts[dram_pkt->bankId]++;
|
||||||
|
} else {
|
||||||
|
if (rowHitFlag)
|
||||||
|
writeRowHits++;
|
||||||
|
bytesWritten += burstSize;
|
||||||
|
perBankWrBursts[dram_pkt->bankId]++;
|
||||||
|
|
||||||
// At this point, commonality between reads and writes ends.
|
// At this point, commonality between reads and writes ends.
|
||||||
// For writes, we are done since we long ago responded to the
|
// For writes, we are done since we long ago responded to the
|
||||||
// requestor. We also don't care about stats for writes. For
|
// requestor.
|
||||||
// reads, we still need to figure out respoding to the requestor,
|
|
||||||
// and capture stats.
|
|
||||||
|
|
||||||
if (!dram_pkt->isRead) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update stats
|
// Update latency stats
|
||||||
totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime;
|
totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime;
|
||||||
totBankLat += bankLat;
|
totBankLat += bankLat;
|
||||||
totBusLat += tBURST;
|
totBusLat += tBURST;
|
||||||
|
@ -1348,103 +1342,106 @@ SimpleDRAM::regStats()
|
||||||
|
|
||||||
readReqs
|
readReqs
|
||||||
.name(name() + ".readReqs")
|
.name(name() + ".readReqs")
|
||||||
.desc("Total number of read requests accepted by DRAM controller");
|
.desc("Number of read requests accepted");
|
||||||
|
|
||||||
writeReqs
|
writeReqs
|
||||||
.name(name() + ".writeReqs")
|
.name(name() + ".writeReqs")
|
||||||
.desc("Total number of write requests accepted by DRAM controller");
|
.desc("Number of write requests accepted");
|
||||||
|
|
||||||
readBursts
|
readBursts
|
||||||
.name(name() + ".readBursts")
|
.name(name() + ".readBursts")
|
||||||
.desc("Total number of DRAM read bursts. "
|
.desc("Number of DRAM read bursts, "
|
||||||
"Each DRAM read request translates to either one or multiple "
|
"including those serviced by the write queue");
|
||||||
"DRAM read bursts");
|
|
||||||
|
|
||||||
writeBursts
|
writeBursts
|
||||||
.name(name() + ".writeBursts")
|
.name(name() + ".writeBursts")
|
||||||
.desc("Total number of DRAM write bursts. "
|
.desc("Number of DRAM write bursts, "
|
||||||
"Each DRAM write request translates to either one or multiple "
|
"including those merged in the write queue");
|
||||||
"DRAM write bursts");
|
|
||||||
|
|
||||||
servicedByWrQ
|
servicedByWrQ
|
||||||
.name(name() + ".servicedByWrQ")
|
.name(name() + ".servicedByWrQ")
|
||||||
.desc("Number of DRAM read bursts serviced by write Q");
|
.desc("Number of DRAM read bursts serviced by the write queue");
|
||||||
|
|
||||||
|
mergedWrBursts
|
||||||
|
.name(name() + ".mergedWrBursts")
|
||||||
|
.desc("Number of DRAM write bursts merged with an existing one");
|
||||||
|
|
||||||
neitherReadNorWrite
|
neitherReadNorWrite
|
||||||
.name(name() + ".neitherReadNorWrite")
|
.name(name() + ".neitherReadNorWriteReqs")
|
||||||
.desc("Reqs where no action is needed");
|
.desc("Number of requests that are neither read nor write");
|
||||||
|
|
||||||
perBankRdReqs
|
perBankRdBursts
|
||||||
.init(banksPerRank * ranksPerChannel)
|
.init(banksPerRank * ranksPerChannel)
|
||||||
.name(name() + ".perBankRdReqs")
|
.name(name() + ".perBankRdBursts")
|
||||||
.desc("Track reads on a per bank basis");
|
.desc("Per bank write bursts");
|
||||||
|
|
||||||
perBankWrReqs
|
perBankWrBursts
|
||||||
.init(banksPerRank * ranksPerChannel)
|
.init(banksPerRank * ranksPerChannel)
|
||||||
.name(name() + ".perBankWrReqs")
|
.name(name() + ".perBankWrBursts")
|
||||||
.desc("Track writes on a per bank basis");
|
.desc("Per bank write bursts");
|
||||||
|
|
||||||
avgRdQLen
|
avgRdQLen
|
||||||
.name(name() + ".avgRdQLen")
|
.name(name() + ".avgRdQLen")
|
||||||
.desc("Average read queue length over time")
|
.desc("Average read queue length when enqueuing")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
avgWrQLen
|
avgWrQLen
|
||||||
.name(name() + ".avgWrQLen")
|
.name(name() + ".avgWrQLen")
|
||||||
.desc("Average write queue length over time")
|
.desc("Average write queue length when enqueuing")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
totQLat
|
totQLat
|
||||||
.name(name() + ".totQLat")
|
.name(name() + ".totQLat")
|
||||||
.desc("Total cycles spent in queuing delays");
|
.desc("Total ticks spent queuing");
|
||||||
|
|
||||||
totBankLat
|
totBankLat
|
||||||
.name(name() + ".totBankLat")
|
.name(name() + ".totBankLat")
|
||||||
.desc("Total cycles spent in bank access");
|
.desc("Total ticks spent accessing banks");
|
||||||
|
|
||||||
totBusLat
|
totBusLat
|
||||||
.name(name() + ".totBusLat")
|
.name(name() + ".totBusLat")
|
||||||
.desc("Total cycles spent in databus access");
|
.desc("Total ticks spent in databus transfers");
|
||||||
|
|
||||||
totMemAccLat
|
totMemAccLat
|
||||||
.name(name() + ".totMemAccLat")
|
.name(name() + ".totMemAccLat")
|
||||||
.desc("Sum of mem lat for all requests");
|
.desc("Total ticks spent from burst creation until serviced "
|
||||||
|
"by the DRAM");
|
||||||
|
|
||||||
avgQLat
|
avgQLat
|
||||||
.name(name() + ".avgQLat")
|
.name(name() + ".avgQLat")
|
||||||
.desc("Average queueing delay per request")
|
.desc("Average queueing delay per DRAM burst")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
avgQLat = totQLat / (readBursts - servicedByWrQ);
|
avgQLat = totQLat / (readBursts - servicedByWrQ);
|
||||||
|
|
||||||
avgBankLat
|
avgBankLat
|
||||||
.name(name() + ".avgBankLat")
|
.name(name() + ".avgBankLat")
|
||||||
.desc("Average bank access latency per request")
|
.desc("Average bank access latency per DRAM burst")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
avgBankLat = totBankLat / (readBursts - servicedByWrQ);
|
avgBankLat = totBankLat / (readBursts - servicedByWrQ);
|
||||||
|
|
||||||
avgBusLat
|
avgBusLat
|
||||||
.name(name() + ".avgBusLat")
|
.name(name() + ".avgBusLat")
|
||||||
.desc("Average bus latency per request")
|
.desc("Average bus latency per DRAM burst")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
avgBusLat = totBusLat / (readBursts - servicedByWrQ);
|
avgBusLat = totBusLat / (readBursts - servicedByWrQ);
|
||||||
|
|
||||||
avgMemAccLat
|
avgMemAccLat
|
||||||
.name(name() + ".avgMemAccLat")
|
.name(name() + ".avgMemAccLat")
|
||||||
.desc("Average memory access latency")
|
.desc("Average memory access latency per DRAM burst")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
avgMemAccLat = totMemAccLat / (readBursts - servicedByWrQ);
|
avgMemAccLat = totMemAccLat / (readBursts - servicedByWrQ);
|
||||||
|
|
||||||
numRdRetry
|
numRdRetry
|
||||||
.name(name() + ".numRdRetry")
|
.name(name() + ".numRdRetry")
|
||||||
.desc("Number of times rd buffer was full causing retry");
|
.desc("Number of times read queue was full causing retry");
|
||||||
|
|
||||||
numWrRetry
|
numWrRetry
|
||||||
.name(name() + ".numWrRetry")
|
.name(name() + ".numWrRetry")
|
||||||
.desc("Number of times wr buffer was full causing retry");
|
.desc("Number of times write queue was full causing retry");
|
||||||
|
|
||||||
readRowHits
|
readRowHits
|
||||||
.name(name() + ".readRowHits")
|
.name(name() + ".readRowHits")
|
||||||
|
@ -1466,17 +1463,17 @@ SimpleDRAM::regStats()
|
||||||
.desc("Row buffer hit rate for writes")
|
.desc("Row buffer hit rate for writes")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
writeRowHitRate = (writeRowHits / writeBursts) * 100;
|
writeRowHitRate = (writeRowHits / (writeBursts - mergedWrBursts)) * 100;
|
||||||
|
|
||||||
readPktSize
|
readPktSize
|
||||||
.init(ceilLog2(burstSize) + 1)
|
.init(ceilLog2(burstSize) + 1)
|
||||||
.name(name() + ".readPktSize")
|
.name(name() + ".readPktSize")
|
||||||
.desc("Categorize read packet sizes");
|
.desc("Read request sizes (log2)");
|
||||||
|
|
||||||
writePktSize
|
writePktSize
|
||||||
.init(ceilLog2(burstSize) + 1)
|
.init(ceilLog2(burstSize) + 1)
|
||||||
.name(name() + ".writePktSize")
|
.name(name() + ".writePktSize")
|
||||||
.desc("Categorize write packet sizes");
|
.desc("Write request sizes (log2)");
|
||||||
|
|
||||||
rdQLenPdf
|
rdQLenPdf
|
||||||
.init(readBufferSize)
|
.init(readBufferSize)
|
||||||
|
@ -1504,47 +1501,47 @@ SimpleDRAM::regStats()
|
||||||
|
|
||||||
bytesWritten
|
bytesWritten
|
||||||
.name(name() + ".bytesWritten")
|
.name(name() + ".bytesWritten")
|
||||||
.desc("Total number of bytes written to memory");
|
.desc("Total number of bytes written to DRAM");
|
||||||
|
|
||||||
bytesConsumedRd
|
bytesReadSys
|
||||||
.name(name() + ".bytesConsumedRd")
|
.name(name() + ".bytesReadSys")
|
||||||
.desc("bytesRead derated as per pkt->getSize()");
|
.desc("Total read bytes from the system interface side");
|
||||||
|
|
||||||
bytesConsumedWr
|
bytesWrittenSys
|
||||||
.name(name() + ".bytesConsumedWr")
|
.name(name() + ".bytesWrittenSys")
|
||||||
.desc("bytesWritten derated as per pkt->getSize()");
|
.desc("Total written bytes from the system interface side");
|
||||||
|
|
||||||
avgRdBW
|
avgRdBW
|
||||||
.name(name() + ".avgRdBW")
|
.name(name() + ".avgRdBW")
|
||||||
.desc("Average achieved read bandwidth in MB/s")
|
.desc("Average DRAM read bandwidth in MiByte/s")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
avgRdBW = ((bytesReadDRAM + bytesReadWrQ) / 1000000) / simSeconds;
|
avgRdBW = (bytesReadDRAM / 1000000) / simSeconds;
|
||||||
|
|
||||||
avgWrBW
|
avgWrBW
|
||||||
.name(name() + ".avgWrBW")
|
.name(name() + ".avgWrBW")
|
||||||
.desc("Average achieved write bandwidth in MB/s")
|
.desc("Average achieved write bandwidth in MiByte/s")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
avgWrBW = (bytesWritten / 1000000) / simSeconds;
|
avgWrBW = (bytesWritten / 1000000) / simSeconds;
|
||||||
|
|
||||||
avgConsumedRdBW
|
avgRdBWSys
|
||||||
.name(name() + ".avgConsumedRdBW")
|
.name(name() + ".avgRdBWSys")
|
||||||
.desc("Average consumed read bandwidth in MB/s")
|
.desc("Average system read bandwidth in MiByte/s")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
avgConsumedRdBW = (bytesConsumedRd / 1000000) / simSeconds;
|
avgRdBWSys = (bytesReadSys / 1000000) / simSeconds;
|
||||||
|
|
||||||
avgConsumedWrBW
|
avgWrBWSys
|
||||||
.name(name() + ".avgConsumedWrBW")
|
.name(name() + ".avgWrBWSys")
|
||||||
.desc("Average consumed write bandwidth in MB/s")
|
.desc("Average system write bandwidth in MiByte/s")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
avgConsumedWrBW = (bytesConsumedWr / 1000000) / simSeconds;
|
avgWrBWSys = (bytesWrittenSys / 1000000) / simSeconds;
|
||||||
|
|
||||||
peakBW
|
peakBW
|
||||||
.name(name() + ".peakBW")
|
.name(name() + ".peakBW")
|
||||||
.desc("Theoretical peak bandwidth in MB/s")
|
.desc("Theoretical peak bandwidth in MiByte/s")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
peakBW = (SimClock::Frequency / tBURST) * burstSize / 1000000;
|
peakBW = (SimClock::Frequency / tBURST) * burstSize / 1000000;
|
||||||
|
@ -1587,8 +1584,8 @@ SimpleDRAM::regStats()
|
||||||
.desc("Row buffer hit rate, read and write combined")
|
.desc("Row buffer hit rate, read and write combined")
|
||||||
.precision(2);
|
.precision(2);
|
||||||
|
|
||||||
pageHitRate = (writeRowHits + readRowHits) / (writeReqs + readReqs -
|
pageHitRate = (writeRowHits + readRowHits) /
|
||||||
servicedByWrQ) * 100;
|
(writeBursts - mergedWrBursts + readBursts - servicedByWrQ) * 100;
|
||||||
|
|
||||||
prechargeAllPercent
|
prechargeAllPercent
|
||||||
.name(name() + ".prechargeAllPercent")
|
.name(name() + ".prechargeAllPercent")
|
||||||
|
|
|
@ -547,12 +547,13 @@ class SimpleDRAM : public AbstractMemory
|
||||||
Stats::Scalar bytesReadDRAM;
|
Stats::Scalar bytesReadDRAM;
|
||||||
Stats::Scalar bytesReadWrQ;
|
Stats::Scalar bytesReadWrQ;
|
||||||
Stats::Scalar bytesWritten;
|
Stats::Scalar bytesWritten;
|
||||||
Stats::Scalar bytesConsumedRd;
|
Stats::Scalar bytesReadSys;
|
||||||
Stats::Scalar bytesConsumedWr;
|
Stats::Scalar bytesWrittenSys;
|
||||||
Stats::Scalar servicedByWrQ;
|
Stats::Scalar servicedByWrQ;
|
||||||
|
Stats::Scalar mergedWrBursts;
|
||||||
Stats::Scalar neitherReadNorWrite;
|
Stats::Scalar neitherReadNorWrite;
|
||||||
Stats::Vector perBankRdReqs;
|
Stats::Vector perBankRdBursts;
|
||||||
Stats::Vector perBankWrReqs;
|
Stats::Vector perBankWrBursts;
|
||||||
Stats::Scalar numRdRetry;
|
Stats::Scalar numRdRetry;
|
||||||
Stats::Scalar numWrRetry;
|
Stats::Scalar numWrRetry;
|
||||||
Stats::Scalar totGap;
|
Stats::Scalar totGap;
|
||||||
|
@ -577,8 +578,8 @@ class SimpleDRAM : public AbstractMemory
|
||||||
// Average bandwidth
|
// Average bandwidth
|
||||||
Stats::Formula avgRdBW;
|
Stats::Formula avgRdBW;
|
||||||
Stats::Formula avgWrBW;
|
Stats::Formula avgWrBW;
|
||||||
Stats::Formula avgConsumedRdBW;
|
Stats::Formula avgRdBWSys;
|
||||||
Stats::Formula avgConsumedWrBW;
|
Stats::Formula avgWrBWSys;
|
||||||
Stats::Formula peakBW;
|
Stats::Formula peakBW;
|
||||||
Stats::Formula busUtil;
|
Stats::Formula busUtil;
|
||||||
Stats::Formula busUtilRead;
|
Stats::Formula busUtilRead;
|
||||||
|
|
Loading…
Reference in a new issue