summaryrefslogtreecommitdiff
path: root/src/mem/simple_dram.cc
diff options
context:
space:
mode:
authorAndreas Hansson <andreas.hansson@arm.com>2014-03-23 11:12:01 -0400
committerAndreas Hansson <andreas.hansson@arm.com>2014-03-23 11:12:01 -0400
commit6557741311f28f718cc33f9abde36d7e51f3585c (patch)
treef5d77bce64a777801d40ef9901cff9b1c17c69c8 /src/mem/simple_dram.cc
parent7d883df7e58b6e61ed93717f6fde251086d50153 (diff)
downloadgem5-6557741311f28f718cc33f9abde36d7e51f3585c.tar.xz
mem: Make DRAM write queue draining more aggressive
This patch changes the triggering condition for the write draining such that we grab the opportunity to issue writes if there are no reads waiting (as opposed to waiting for the writes to reach the high threshold). As a result, we potentially drain some of the writes in read idle periods (if any). A low threshold is added to be able to control how many write bursts are kept in the memory controller queue (acting as on-chip storage). The high and low thresholds are updated to sensible values for a 32/64 size write buffer. Note that the thresholds should be adjusted along with the queue sizes. This patch also adds some basic initialisation sanity checks and moves part of the initialisation to the constructor.
Diffstat (limited to 'src/mem/simple_dram.cc')
-rw-r--r--src/mem/simple_dram.cc86
1 files changed, 40 insertions, 46 deletions
diff --git a/src/mem/simple_dram.cc b/src/mem/simple_dram.cc
index 415f3dfcf..9a0008569 100644
--- a/src/mem/simple_dram.cc
+++ b/src/mem/simple_dram.cc
@@ -63,12 +63,14 @@ SimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) :
devicesPerRank(p->devices_per_rank),
burstSize((devicesPerRank * burstLength * deviceBusWidth) / 8),
rowBufferSize(devicesPerRank * deviceRowBufferSize),
+ columnsPerRowBuffer(rowBufferSize / burstSize),
ranksPerChannel(p->ranks_per_channel),
banksPerRank(p->banks_per_rank), channels(p->channels), rowsPerBank(0),
readBufferSize(p->read_buffer_size),
writeBufferSize(p->write_buffer_size),
- writeHighThresholdPerc(p->write_high_thresh_perc),
- writeLowThresholdPerc(p->write_low_thresh_perc),
+ writeHighThreshold(writeBufferSize * p->write_high_thresh_perc / 100.0),
+ writeLowThreshold(writeBufferSize * p->write_low_thresh_perc / 100.0),
+ minWritesPerSwitch(p->min_writes_per_switch), writesThisTime(0),
tWTR(p->tWTR), tBURST(p->tBURST),
tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP), tRAS(p->tRAS),
tRFC(p->tRFC), tREFI(p->tREFI), tRRD(p->tRRD),
@@ -79,8 +81,7 @@ SimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) :
backendLatency(p->static_backend_latency),
busBusyUntil(0), writeStartTime(0),
prevArrival(0), numReqs(0),
- numWritesThisTime(0), newTime(0),
- startTickPrechargeAll(0), numBanksActive(0)
+ newTime(0), startTickPrechargeAll(0), numBanksActive(0)
{
// create the bank states based on the dimensions of the ranks and
// banks
@@ -91,24 +92,11 @@ SimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) :
actTicks[c].resize(activationLimit, 0);
}
- // round the write thresholds percent to a whole number of entries
- // in the buffer.
- writeHighThreshold = writeBufferSize * writeHighThresholdPerc / 100.0;
- writeLowThreshold = writeBufferSize * writeLowThresholdPerc / 100.0;
-}
-
-void
-SimpleDRAM::init()
-{
- if (!port.isConnected()) {
- fatal("SimpleDRAM %s is unconnected!\n", name());
- } else {
- port.sendRangeChange();
- }
-
- // we could deal with plenty options here, but for now do a quick
- // sanity check
- DPRINTF(DRAM, "Burst size %d bytes\n", burstSize);
+ // perform a basic check of the write thresholds
+ if (p->write_low_thresh_perc >= p->write_high_thresh_perc)
+ fatal("Write buffer low threshold %d must be smaller than the "
+ "high threshold %d\n", p->write_low_thresh_perc,
+ p->write_high_thresh_perc);
// determine the rows per bank by looking at the total capacity
uint64_t capacity = ULL(1) << ceilLog2(AbstractMemory::size());
@@ -116,8 +104,6 @@ SimpleDRAM::init()
DPRINTF(DRAM, "Memory capacity %lld (%lld) bytes\n", capacity,
AbstractMemory::size());
- columnsPerRowBuffer = rowBufferSize / burstSize;
-
DPRINTF(DRAM, "Row buffer size %d bytes with %d columns per row buffer\n",
rowBufferSize, columnsPerRowBuffer);
@@ -147,6 +133,16 @@ SimpleDRAM::init()
}
void
+SimpleDRAM::init()
+{
+ if (!port.isConnected()) {
+ fatal("SimpleDRAM %s is unconnected!\n", name());
+ } else {
+ port.sendRangeChange();
+ }
+}
+
+void
SimpleDRAM::startup()
{
// print the configuration of the controller
@@ -397,29 +393,26 @@ SimpleDRAM::processWriteEvent()
writeQueue.pop_front();
delete dram_pkt;
- numWritesThisTime++;
- DPRINTF(DRAM, "Completed %d writes, bus busy for %lld ticks,"\
- "banks busy for %lld ticks\n", numWritesThisTime,
- busBusyUntil - temp1, maxBankFreeAt() - temp2);
+ ++writesThisTime;
+
+ DPRINTF(DRAM, "Writing, bus busy for %lld ticks, banks busy "
+ "for %lld ticks\n", busBusyUntil - temp1, maxBankFreeAt() - temp2);
// Update stats
avgWrQLen = writeQueue.size();
- if (numWritesThisTime >= writeHighThreshold) {
- DPRINTF(DRAM, "Hit write threshold %d\n", writeHighThreshold);
- }
-
- // If number of writes in the queue fall below the low thresholds and
- // read queue is not empty then schedule a request event else continue
- // with writes. The retry above could already have caused it to be
- // scheduled, so first check
- if (((writeQueue.size() <= writeLowThreshold) && !readQueue.empty()) ||
- writeQueue.empty()) {
- numWritesThisTime = 0;
+ // If we emptied the write queue, or got below the threshold and
+ // are not draining, or we have reads waiting and have done enough
+ // writes, then switch to reads. The retry above could already
+ // have caused it to be scheduled, so first check
+ if (writeQueue.empty() ||
+ (writeQueue.size() < writeLowThreshold && !drainManager) ||
+ (!readQueue.empty() && writesThisTime >= minWritesPerSwitch)) {
// turn the bus back around for reads again
busBusyUntil += tWTR;
stopReads = false;
+ writesThisTime = 0;
if (!nextReqEvent.scheduled())
schedule(nextReqEvent, busBusyUntil);
@@ -600,12 +593,13 @@ SimpleDRAM::printParams() const
"Memory controller %s characteristics\n" \
"Read buffer size %d\n" \
"Write buffer size %d\n" \
- "Write buffer thresh %d\n" \
+ "Write high thresh %d\n" \
+ "Write low thresh %d\n" \
"Scheduler %s\n" \
"Address mapping %s\n" \
"Page policy %s\n",
name(), readBufferSize, writeBufferSize, writeHighThreshold,
- scheduler, address_mapping, page_policy);
+ writeLowThreshold, scheduler, address_mapping, page_policy);
DPRINTF(DRAM, "Memory controller %s timing specs\n" \
"tRCD %d ticks\n" \
@@ -1258,11 +1252,11 @@ SimpleDRAM::scheduleNextReq()
// Figure out which read request goes next, and move it to the
// front of the read queue
if (!chooseNextRead()) {
- // In the case there is no read request to go next, see if we
- // are asked to drain, and if so trigger writes, this also
- // ensures that if we hit the write limit we will do this
- // multiple times until we are completely drained
- if (drainManager && !writeQueue.empty() && !writeEvent.scheduled())
+ // In the case there is no read request to go next, trigger
+ // writes if we have passed the low threshold (or if we are
+ // draining)
+ if (!writeQueue.empty() && !writeEvent.scheduled() &&
+ (writeQueue.size() > writeLowThreshold || drainManager))
triggerWrites();
} else {
doDRAMAccess(readQueue.front());