From bb572663cf1ba802492743f1196eb9eac4c20bea Mon Sep 17 00:00:00 2001 From: Andreas Hansson Date: Fri, 1 Nov 2013 11:56:26 -0400 Subject: [PATCH] mem: Add a simple adaptive version of the open-page policy This patch adds a basic adaptive version of the open-page policy that guides the decision to keep open or close by looking at the contents of the controller queues. If no row hits are found, and bank conflicts are present, then the row is closed by means of an auto precharge. This is a well-known technique that should improve performance in most use-cases. --- src/mem/SimpleDRAM.py | 4 ++-- src/mem/simple_dram.cc | 53 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/mem/SimpleDRAM.py b/src/mem/SimpleDRAM.py index c450f8992..b16aa6003 100644 --- a/src/mem/SimpleDRAM.py +++ b/src/mem/SimpleDRAM.py @@ -53,8 +53,8 @@ class MemSched(Enum): vals = ['fcfs', 'frfcfs'] # open row. For a closed-page policy, CoRaBaCh maximises parallelism. class AddrMap(Enum): vals = ['RaBaChCo', 'RaBaCoCh', 'CoRaBaCh'] -# Enum for the page policy, either open or close. -class PageManage(Enum): vals = ['open', 'close'] +# Enum for the page policy, either open, open_adaptive or close. +class PageManage(Enum): vals = ['open', 'open_adaptive', 'close'] # SimpleDRAM is a single-channel single-ported DRAM controller model # that aims to model the most important system-level performance diff --git a/src/mem/simple_dram.cc b/src/mem/simple_dram.cc index 2d46b8522..69209fb8a 100644 --- a/src/mem/simple_dram.cc +++ b/src/mem/simple_dram.cc @@ -598,7 +598,8 @@ SimpleDRAM::printParams() const string scheduler = memSchedPolicy == Enums::fcfs ? "FCFS" : "FR-FCFS"; string address_mapping = addrMapping == Enums::RaBaChCo ? "RaBaChCo" : (addrMapping == Enums::RaBaCoCh ? "RaBaCoCh" : "CoRaBaCh"); - string page_policy = pageMgmt == Enums::open ? "OPEN" : "CLOSE"; + string page_policy = pageMgmt == Enums::open ? "OPEN" : + (pageMgmt == Enums::open_adaptive ? "OPEN (adaptive)" : "CLOSE"); DPRINTF(DRAM, "Memory controller %s characteristics\n" \ @@ -924,7 +925,8 @@ SimpleDRAM::estimateLatency(DRAMPacket* dram_pkt, Tick inTime) Tick potentialActTick; const Bank& bank = dram_pkt->bankRef; - if (pageMgmt == Enums::open) { // open-page policy + // open-page policy + if (pageMgmt == Enums::open || pageMgmt == Enums::open_adaptive) { if (bank.openRow == dram_pkt->row) { // When we have a row-buffer hit, // we don't care about tRAS having expired or not, @@ -955,13 +957,17 @@ SimpleDRAM::estimateLatency(DRAMPacket* dram_pkt, Tick inTime) if (freeTime > inTime) accLat += freeTime - inTime; + // If the there is no open row (open adaptive), then there + // is no precharge delay, otherwise go with tRP + Tick precharge_delay = bank.openRow == -1 ? 0 : tRP; + //The bank is free, and you may be able to activate - potentialActTick = inTime + accLat + tRP; + potentialActTick = inTime + accLat + precharge_delay; if (potentialActTick < bank.actAllowedAt) accLat += bank.actAllowedAt - potentialActTick; - accLat += tRP + tRCD + tCL; - bankLat += tRP + tRCD + tCL; + accLat += precharge_delay + tRCD + tCL; + bankLat += precharge_delay + tRCD + tCL; } } else if (pageMgmt == Enums::close) { // With a close page policy, no notion of @@ -1067,7 +1073,7 @@ SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt) Bank& bank = dram_pkt->bankRef; // Update bank state - if (pageMgmt == Enums::open) { + if (pageMgmt == Enums::open || pageMgmt == Enums::open_adaptive) { bank.openRow = dram_pkt->row; bank.freeAt = curTick() + addDelay + accessLat; bank.bytesAccessed += burstSize; @@ -1085,6 +1091,41 @@ SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt) bytesPerActivate.sample(bank.bytesAccessed); bank.bytesAccessed = 0; } + + if (pageMgmt == Enums::open_adaptive) { + // a twist on the open page policy is to not blindly keep the + // page open, but close it if there are no row hits, and there + // are bank conflicts in the queue + bool got_more_hits = false; + bool got_bank_conflict = false; + + // either look at the read queue or write queue + const deque& queue = dram_pkt->isRead ? readQueue : + writeQueue; + auto p = queue.begin(); + // make sure we are not considering the packet that we are + // currently dealing with (which is the head of the queue) + ++p; + + // keep on looking until we have found both or reached + // the end + while (!(got_more_hits && got_bank_conflict) && + p != queue.end()) { + bool same_rank_bank = (dram_pkt->rank == (*p)->rank) && + (dram_pkt->bank == (*p)->bank); + bool same_row = dram_pkt->row == (*p)->row; + got_more_hits |= same_rank_bank && same_row; + got_bank_conflict |= same_rank_bank && !same_row; + ++p; + } + + // auto pre-charge + if (!got_more_hits && got_bank_conflict) { + bank.openRow = -1; + bank.freeAt = std::max(bank.freeAt, bank.tRASDoneAt) + tRP; + } + } + DPRINTF(DRAM, "doDRAMAccess::bank.freeAt is %lld\n", bank.freeAt); } else if (pageMgmt == Enums::close) { actTick = curTick() + addDelay + accessLat - tRCD - tCL; -- 2.30.2