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:
Andreas Hansson 2013-11-01 11:56:31 -04:00
parent ce93982cc6
commit 460cc77d6d
2 changed files with 84 additions and 86 deletions

View file

@ -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();
// At this point, commonality between reads and writes ends. // Update the access related stats
// For writes, we are done since we long ago responded to the if (dram_pkt->isRead) {
// requestor. We also don't care about stats for writes. For if (rowHitFlag)
// reads, we still need to figure out respoding to the requestor, readRowHits++;
// and capture stats. bytesReadDRAM += burstSize;
perBankRdBursts[dram_pkt->bankId]++;
} else {
if (rowHitFlag)
writeRowHits++;
bytesWritten += burstSize;
perBankWrBursts[dram_pkt->bankId]++;
if (!dram_pkt->isRead) { // At this point, commonality between reads and writes ends.
// For writes, we are done since we long ago responded to the
// requestor.
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")

View file

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