summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Hansson <andreas.hansson@arm.com>2013-08-19 03:52:31 -0400
committerAndreas Hansson <andreas.hansson@arm.com>2013-08-19 03:52:31 -0400
commitac42db8134bff8617e20e1a034dc0d65158335ae (patch)
tree3bd964c031f0bc271da2444152b2f686a3f81f36
parent243f135e5f4a4ec5b4a483f8f9ee90e88d750a2a (diff)
downloadgem5-ac42db8134bff8617e20e1a034dc0d65158335ae.tar.xz
mem: Perform write merging in the DRAM write queue
This patch implements basic write merging in the DRAM to avoid redundant bursts. When a new access is added to the queue it is compared against the existing entries, and if it is either intersecting or immediately succeeding/preceeding an existing item it is merged. There is currently no attempt made at avoiding iterating over the existing items in determining whether merging is possible or not.
-rw-r--r--src/mem/simple_dram.cc92
-rw-r--r--src/mem/simple_dram.hh4
2 files changed, 81 insertions, 15 deletions
diff --git a/src/mem/simple_dram.cc b/src/mem/simple_dram.cc
index faeedbb2b..e8c1dfbcd 100644
--- a/src/mem/simple_dram.cc
+++ b/src/mem/simple_dram.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2012 ARM Limited
+ * Copyright (c) 2010-2013 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -312,7 +312,10 @@ SimpleDRAM::addToReadQueue(PacketPtr pkt, unsigned int pktCount)
bool foundInWrQ = false;
list<DRAMPacket*>::const_iterator i;
for (i = writeQueue.begin(); i != writeQueue.end(); ++i) {
- if ((*i)->addr == addr && (*i)->size >= size){
+ // check if the read is subsumed in the write entry we are
+ // looking at
+ if ((*i)->addr <= addr &&
+ (addr + size) <= ((*i)->addr + (*i)->size)) {
foundInWrQ = true;
servicedByWrQ++;
pktsServicedByWrQ++;
@@ -394,6 +397,10 @@ SimpleDRAM::processWriteEvent()
chooseNextWrite();
DRAMPacket* dram_pkt = writeQueue.front();
+
+ // sanity check
+ assert(dram_pkt->size <= burstSize);
+
// What's the earliest the request can be put on the bus
Tick schedTime = std::max(curTick(), busBusyUntil);
@@ -513,23 +520,79 @@ SimpleDRAM::addToWriteQueue(PacketPtr pkt, unsigned int pktCount)
writePktSize[ceilLog2(size)]++;
writeBursts++;
- DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size);
+ // see if we can merge with an existing item in the write
+ // queue and keep track of whether we have merged or not, as
+ // there is only ever one item to merge with
+ bool merged = false;
+ auto w = writeQueue.begin();
+
+ while(!merged && w != writeQueue.end()) {
+ // either of the two could be first, if they are the same
+ // it does not matter which way we go
+ if ((*w)->addr >= addr) {
+ if ((addr + size) >= ((*w)->addr + (*w)->size)) {
+ // check if the existing one is completely
+ // subsumed in the new one
+ DPRINTF(DRAM, "Merging write covering existing burst\n");
+ merged = true;
+ // update both the address and the size
+ (*w)->addr = addr;
+ (*w)->size = size;
+ } else if ((addr + size) >= (*w)->addr &&
+ ((*w)->addr + (*w)->size - addr) <= burstSize) {
+ // the new one is just before or partially
+ // overlapping with the existing one, and together
+ // they fit within a burst
+ DPRINTF(DRAM, "Merging write before existing burst\n");
+ merged = true;
+ // the existing queue item needs to be adjusted with
+ // respect to both address and size
+ (*w)->addr = addr;
+ (*w)->size = (*w)->addr + (*w)->size - addr;
+ }
+ } else {
+ if (((*w)->addr + (*w)->size) >= (addr + size)) {
+ // check if the new one is completely subsumed in the
+ // existing one
+ DPRINTF(DRAM, "Merging write into existing burst\n");
+ merged = true;
+ // no adjustments necessary
+ } else if (((*w)->addr + (*w)->size) >= addr &&
+ (addr + size - (*w)->addr) <= burstSize) {
+ // the existing one is just before or partially
+ // overlapping with the new one, and together
+ // they fit within a burst
+ DPRINTF(DRAM, "Merging write after existing burst\n");
+ merged = true;
+ // the address is right, and only the size has
+ // to be adjusted
+ (*w)->size = addr + size - (*w)->addr;
+ }
+ }
+ ++w;
+ }
- assert(writeQueue.size() < writeBufferSize);
- wrQLenPdf[writeQueue.size()]++;
+ // if the item was not merged we need to create a new write
+ // and enqueue it
+ if (!merged) {
+ DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size);
- DPRINTF(DRAM, "Adding to write queue\n");
+ assert(writeQueue.size() < writeBufferSize);
+ wrQLenPdf[writeQueue.size()]++;
- writeQueue.push_back(dram_pkt);
+ DPRINTF(DRAM, "Adding to write queue\n");
- // Update stats
- uint32_t bank_id = banksPerRank * dram_pkt->rank + dram_pkt->bank;
- assert(bank_id < ranksPerChannel * banksPerRank);
- perBankWrReqs[bank_id]++;
+ writeQueue.push_back(dram_pkt);
- avgWrQLen = writeQueue.size();
+ // Update stats
+ uint32_t bank_id = banksPerRank * dram_pkt->rank + dram_pkt->bank;
+ assert(bank_id < ranksPerChannel * banksPerRank);
+ perBankWrReqs[bank_id]++;
+
+ avgWrQLen = writeQueue.size();
+ }
- bytesConsumedWr += dram_pkt->size;
+ bytesConsumedWr += size;
bytesWritten += burstSize;
// Starting address of next dram pkt (aligend to burstSize boundary)
@@ -1077,6 +1140,9 @@ SimpleDRAM::moveToRespQ()
DRAMPacket* dram_pkt = readQueue.front();
readQueue.pop_front();
+ // sanity check
+ assert(dram_pkt->size <= burstSize);
+
// Insert into response queue sorted by readyTime
// It will be sent back to the requestor at its
// readyTime
diff --git a/src/mem/simple_dram.hh b/src/mem/simple_dram.hh
index 313ad067b..9473f010f 100644
--- a/src/mem/simple_dram.hh
+++ b/src/mem/simple_dram.hh
@@ -209,13 +209,13 @@ class SimpleDRAM : public AbstractMemory
* reason is to keep the address offset so we can accurately check
* incoming read packets with packets in the write queue.
*/
- const Addr addr;
+ Addr addr;
/**
* The size of this dram packet in bytes
* It is always equal or smaller than DRAM burst size
*/
- const unsigned int size;
+ unsigned int size;
/**
* A pointer to the BurstHelper if this DRAMPacket is a split packet