mem: Add bytes per activate DRAM controller stat
authorAndreas Hansson <andreas.hansson@arm.com>
Thu, 30 May 2013 16:54:13 +0000 (12:54 -0400)
committerAndreas Hansson <andreas.hansson@arm.com>
Thu, 30 May 2013 16:54:13 +0000 (12:54 -0400)
This patch adds a histogram to track how many bytes are accessed in an
open row before it is closed. This metric is useful in characterising
a workload and the efficiency of the DRAM scheduler. For example, a
DDR3-1600 device requires 44 cycles (tRC) before it can activate
another row in the same bank. For a x32 interface (8 bytes per cycle)
that means 8 x 44 = 352 bytes must be transferred to hide the
preparation time.

src/mem/simple_dram.cc
src/mem/simple_dram.hh

index c549474384108ce6eeaf3b75bf054ddb6ab9c6b2..bd3a70d253d1aff7006836781f77ae0024b11560 100644 (file)
@@ -363,11 +363,17 @@ SimpleDRAM::processWriteEvent()
             bank.openRow = dram_pkt->row;
             bank.freeAt = schedTime + tBURST + std::max(accessLat, tCL);
             busBusyUntil = bank.freeAt - tCL;
+            bank.bytesAccessed += bytesPerCacheLine;
 
             if (!rowHitFlag) {
                 bank.tRASDoneAt = bank.freeAt + tRP;
                 recordActivate(bank.freeAt - tCL - tRCD);
                 busBusyUntil = bank.freeAt - tCL - tRCD;
+
+                // sample the number of bytes accessed and reset it as
+                // we are now closing this row
+                bytesPerActivate.sample(bank.bytesAccessed);
+                bank.bytesAccessed = 0;
             }
         } else if (pageMgmt == Enums::close) {
             bank.freeAt = schedTime + tBURST + accessLat + tRP + tRP;
@@ -378,6 +384,7 @@ SimpleDRAM::processWriteEvent()
                     "banks_id %d is %lld\n",
                     dram_pkt->rank * banksPerRank + dram_pkt->bank,
                     bank.freeAt);
+            bytesPerActivate.sample(bytesPerCacheLine);
         } else
             panic("Unknown page management policy chosen\n");
 
@@ -898,6 +905,8 @@ SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt)
     if (pageMgmt == Enums::open) {
         bank.openRow = dram_pkt->row;
         bank.freeAt = curTick() + addDelay + accessLat;
+        bank.bytesAccessed += bytesPerCacheLine;
+
         // If you activated a new row do to this access, the next access
         // will have to respect tRAS for this bank. Assume tRAS ~= 3 * tRP.
         // Also need to account for t_XAW
@@ -905,6 +914,10 @@ SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt)
             bank.tRASDoneAt = bank.freeAt + tRP;
             recordActivate(bank.freeAt - tCL - tRCD); //since this is open page,
                                                       //no tRP by default
+            // sample the number of bytes accessed and reset it as
+            // we are now closing this row
+            bytesPerActivate.sample(bank.bytesAccessed);
+            bank.bytesAccessed = 0;
         }
     } else if (pageMgmt == Enums::close) { // accounting for tRAS also
         // assuming that tRAS ~= 3 * tRP, and tRC ~= 4 * tRP, as is common
@@ -912,6 +925,7 @@ SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt)
         bank.freeAt = curTick() + addDelay + accessLat + tRP + tRP;
         recordActivate(bank.freeAt - tRP - tRP - tCL - tRCD); //essentially (freeAt - tRC)
         DPRINTF(DRAM,"doDRAMAccess::bank.freeAt is %lld\n",bank.freeAt);
+        bytesPerActivate.sample(bytesPerCacheLine);
     } else
         panic("No page management policy chosen\n");
 
@@ -1192,6 +1206,11 @@ SimpleDRAM::regStats()
         .name(name() + ".wrQLenPdf")
         .desc("What write queue length does an incoming req see");
 
+     bytesPerActivate
+         .init(bytesPerCacheLine * linesPerRowBuffer)
+         .name(name() + ".bytesPerActivate")
+         .desc("Bytes accessed per row activation")
+         .flags(nozero);
 
     bytesRead
         .name(name() + ".bytesRead")
index 920dcf33a0a2763e4d7c86c62b45645bcda71d74..e4d20163a65ce9347d3e19ad9c60f8a46d038dcb 100644 (file)
@@ -133,8 +133,10 @@ class SimpleDRAM : public AbstractMemory
     std::deque<Tick> actTicks;
 
     /**
-     * A basic class to track the bank state indirectly via
-     * times "freeAt" and "tRASDoneAt" and what page is currently open
+     * A basic class to track the bank state indirectly via times
+     * "freeAt" and "tRASDoneAt" and what page is currently open. The
+     * bank also keeps track of how many bytes have been accessed in
+     * the open row since it was opened.
      */
     class Bank
     {
@@ -148,7 +150,10 @@ class SimpleDRAM : public AbstractMemory
         Tick freeAt;
         Tick tRASDoneAt;
 
-        Bank() : openRow(INVALID_ROW), freeAt(0), tRASDoneAt(0)
+        uint32_t bytesAccessed;
+
+        Bank() :
+            openRow(INVALID_ROW), freeAt(0), tRASDoneAt(0), bytesAccessed(0)
         { }
     };
 
@@ -452,7 +457,7 @@ class SimpleDRAM : public AbstractMemory
     Stats::Vector writePktSize;
     Stats::Vector rdQLenPdf;
     Stats::Vector wrQLenPdf;
-
+    Stats::Histogram bytesPerActivate;
 
     // Latencies summed over all requests
     Stats::Scalar totQLat;