summaryrefslogtreecommitdiff
path: root/src/mem/dram_ctrl.cc
diff options
context:
space:
mode:
authorAndreas Hansson <andreas.hansson@arm.com>2014-05-09 18:58:48 -0400
committerAndreas Hansson <andreas.hansson@arm.com>2014-05-09 18:58:48 -0400
commitc735ef6cb08f109a614383e12f9f55148bcf0257 (patch)
treead913a46243e17f2bf380df3189536e62a6e0214 /src/mem/dram_ctrl.cc
parent87f4c956c48aa7e66162c73dabba199f7c25638a (diff)
downloadgem5-c735ef6cb08f109a614383e12f9f55148bcf0257.tar.xz
mem: Merge DRAM page-management calculations
This patch treats the closed page policy as yet another case of auto-precharging, and thus merges the code with that used for the other policies.
Diffstat (limited to 'src/mem/dram_ctrl.cc')
-rw-r--r--src/mem/dram_ctrl.cc256
1 files changed, 109 insertions, 147 deletions
diff --git a/src/mem/dram_ctrl.cc b/src/mem/dram_ctrl.cc
index 3774220b5..7062390e8 100644
--- a/src/mem/dram_ctrl.cc
+++ b/src/mem/dram_ctrl.cc
@@ -810,68 +810,48 @@ DRAMCtrl::estimateLatency(DRAMPacket* dram_pkt, Tick inTime)
Tick potentialActTick;
const Bank& bank = dram_pkt->bankRef;
- // open-page policy or close_adaptive policy
- if (pageMgmt == Enums::open || pageMgmt == Enums::open_adaptive ||
- pageMgmt == Enums::close_adaptive) {
- if (bank.openRow == dram_pkt->row) {
- // When we have a row-buffer hit,
- // we don't care about tRAS having expired or not,
- // but do care about bank being free for access
- rowHitFlag = true;
-
- // When a series of requests arrive to the same row,
- // DDR systems are capable of streaming data continuously
- // at maximum bandwidth (subject to tCCD). Here, we approximate
- // this condition, and assume that if whenever a bank is already
- // busy and a new request comes in, it can be completed with no
- // penalty beyond waiting for the existing read to complete.
- if (bank.freeAt > inTime) {
- accLat += bank.freeAt - inTime;
- bankLat += 0;
- } else {
- // CAS latency only
- accLat += tCL;
- bankLat += tCL;
- }
+ if (bank.openRow == dram_pkt->row) {
+ // When we have a row-buffer hit,
+ // we don't care about tRAS having expired or not,
+ // but do care about bank being free for access
+ rowHitFlag = true;
+
+ // When a series of requests arrive to the same row,
+ // DDR systems are capable of streaming data continuously
+ // at maximum bandwidth (subject to tCCD). Here, we approximate
+ // this condition, and assume that if whenever a bank is already
+ // busy and a new request comes in, it can be completed with no
+ // penalty beyond waiting for the existing read to complete.
+ if (bank.freeAt > inTime) {
+ accLat += bank.freeAt - inTime;
+ bankLat += 0;
} else {
- // Row-buffer miss, need to close existing row
- // once tRAS has expired, then open the new one,
- // then add cas latency.
- Tick freeTime = std::max(bank.tRASDoneAt, bank.freeAt);
-
- if (freeTime > inTime)
- accLat += freeTime - inTime;
+ // CAS latency only
+ accLat += tCL;
+ bankLat += tCL;
+ }
+ } else {
+ // Row-buffer miss, need to close existing row
+ // once tRAS has expired, then open the new one,
+ // then add cas latency.
+ Tick freeTime = std::max(bank.tRASDoneAt, bank.freeAt);
- // If the there is no open row (open adaptive), then there
- // is no precharge delay, otherwise go with tRP
- Tick precharge_delay = bank.openRow == Bank::NO_ROW ? 0 : tRP;
+ if (freeTime > inTime)
+ accLat += freeTime - inTime;
- //The bank is free, and you may be able to activate
- potentialActTick = inTime + accLat + precharge_delay;
- if (potentialActTick < bank.actAllowedAt)
- accLat += bank.actAllowedAt - potentialActTick;
-
- accLat += precharge_delay + tRCD + tCL;
- bankLat += precharge_delay + tRCD + tCL;
- }
- } else if (pageMgmt == Enums::close) {
- // With a close page policy, no notion of
- // bank.tRASDoneAt
- if (bank.freeAt > inTime)
- accLat += bank.freeAt - inTime;
+ // If the there is no open row, then there is no precharge
+ // delay, otherwise go with tRP
+ Tick precharge_delay = bank.openRow == Bank::NO_ROW ? 0 : tRP;
//The bank is free, and you may be able to activate
- potentialActTick = inTime + accLat;
+ potentialActTick = inTime + accLat + precharge_delay;
if (potentialActTick < bank.actAllowedAt)
accLat += bank.actAllowedAt - potentialActTick;
- // page already closed, simply open the row, and
- // add cas latency
- accLat += tRCD + tCL;
- bankLat += tRCD + tCL;
- } else
- panic("No page management policy chosen\n");
+ accLat += precharge_delay + tRCD + tCL;
+ bankLat += precharge_delay + tRCD + tCL;
+ }
DPRINTF(DRAM, "Returning < %lld, %lld > from estimateLatency()\n",
bankLat, accLat);
@@ -1033,115 +1013,97 @@ DRAMCtrl::doDRAMAccess(DRAMPacket* dram_pkt)
Bank& bank = dram_pkt->bankRef;
// Update bank state
- if (pageMgmt == Enums::open || pageMgmt == Enums::open_adaptive ||
- pageMgmt == Enums::close_adaptive) {
-
- if (rowHitFlag) {
- bank.freeAt = curTick() + addDelay + accessLat;
- } else {
- // If there is a page open, precharge it.
- if (bank.openRow != Bank::NO_ROW) {
- prechargeBank(bank, std::max(std::max(bank.freeAt,
- bank.tRASDoneAt),
- curTick()) + tRP);
- }
-
- // Any precharge is already part of the latency
- // estimation, so update the bank free time
- bank.freeAt = curTick() + addDelay + accessLat;
-
- // any waiting for banks account for in freeAt
- actTick = bank.freeAt - tCL - tRCD;
-
- // If you activated a new row do to this access, the next access
- // will have to respect tRAS for this bank
- bank.tRASDoneAt = actTick + tRAS;
-
- recordActivate(actTick, dram_pkt->rank, dram_pkt->bank,
- dram_pkt->row);
+ if (rowHitFlag) {
+ bank.freeAt = curTick() + addDelay + accessLat;
+ } else {
+ // If there is a page open, precharge it.
+ if (bank.openRow != Bank::NO_ROW) {
+ prechargeBank(bank, std::max(std::max(bank.freeAt,
+ bank.tRASDoneAt),
+ curTick()) + tRP);
}
- // increment the bytes accessed and the accesses per row
- bank.bytesAccessed += burstSize;
- ++bank.rowAccesses;
-
- // if we reached the max, then issue with an auto-precharge
- bool auto_precharge = bank.rowAccesses == maxAccessesPerRow;
-
- // if we did not hit the limit, we might still want to
- // auto-precharge
- if (!auto_precharge &&
- (pageMgmt == Enums::open_adaptive ||
- pageMgmt == Enums::close_adaptive)) {
- // a twist on the open and close page policies:
- // 1) open_adaptive page policy does not blindly keep the
- // page open, but close it if there are no row hits, and there
- // are bank conflicts in the queue
- // 2) close_adaptive page policy does not blindly close the
- // page, but closes it only if there are no row hits in the queue.
- // In this case, only force an auto precharge when there
- // are no same page hits in the queue
- bool got_more_hits = false;
- bool got_bank_conflict = false;
-
- // either look at the read queue or write queue
- const deque<DRAMPacket*>& 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;
+ // Any precharge is already part of the latency
+ // estimation, so update the bank free time
+ bank.freeAt = curTick() + addDelay + accessLat;
- // keep on looking until we have found required condition or
- // reached the end
- while (!(got_more_hits &&
- (got_bank_conflict || pageMgmt == Enums::close_adaptive)) &&
- 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;
- }
+ // any waiting for banks account for in freeAt
+ actTick = bank.freeAt - tCL - tRCD;
- // auto pre-charge when either
- // 1) open_adaptive policy, we have not got any more hits, and
- // have a bank conflict
- // 2) close_adaptive policy and we have not got any more hits
- auto_precharge = !got_more_hits &&
- (got_bank_conflict || pageMgmt == Enums::close_adaptive);
- }
+ // If you activated a new row do to this access, the next access
+ // will have to respect tRAS for this bank
+ bank.tRASDoneAt = actTick + tRAS;
- // if this access should use auto-precharge, then we are
- // closing the row
- if (auto_precharge) {
- prechargeBank(bank, std::max(bank.freeAt, bank.tRASDoneAt) + tRP);
+ recordActivate(actTick, dram_pkt->rank, dram_pkt->bank,
+ dram_pkt->row);
+ }
- DPRINTF(DRAM, "Auto-precharged bank: %d\n", dram_pkt->bankId);
+ // increment the bytes accessed and the accesses per row
+ bank.bytesAccessed += burstSize;
+ ++bank.rowAccesses;
+
+ // if we reached the max, then issue with an auto-precharge
+ bool auto_precharge = pageMgmt == Enums::close ||
+ bank.rowAccesses == maxAccessesPerRow;
+
+ // if we did not hit the limit, we might still want to
+ // auto-precharge
+ if (!auto_precharge &&
+ (pageMgmt == Enums::open_adaptive ||
+ pageMgmt == Enums::close_adaptive)) {
+ // a twist on the open and close page policies:
+ // 1) open_adaptive page policy does not blindly keep the
+ // page open, but close it if there are no row hits, and there
+ // are bank conflicts in the queue
+ // 2) close_adaptive page policy does not blindly close the
+ // page, but closes it only if there are no row hits in the queue.
+ // In this case, only force an auto precharge when there
+ // are no same page hits in the queue
+ bool got_more_hits = false;
+ bool got_bank_conflict = false;
+
+ // either look at the read queue or write queue
+ const deque<DRAMPacket*>& 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 required condition or
+ // reached the end
+ while (!(got_more_hits &&
+ (got_bank_conflict || pageMgmt == Enums::close_adaptive)) &&
+ 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;
}
- DPRINTF(DRAM, "doDRAMAccess::bank.freeAt is %lld\n", bank.freeAt);
- } else if (pageMgmt == Enums::close) {
- actTick = curTick() + addDelay + accessLat - tRCD - tCL;
- recordActivate(actTick, dram_pkt->rank, dram_pkt->bank, dram_pkt->row);
+ // auto pre-charge when either
+ // 1) open_adaptive policy, we have not got any more hits, and
+ // have a bank conflict
+ // 2) close_adaptive policy and we have not got any more hits
+ auto_precharge = !got_more_hits &&
+ (got_bank_conflict || pageMgmt == Enums::close_adaptive);
+ }
- bank.freeAt = actTick + tRCD + tCL;
- bank.tRASDoneAt = actTick + tRAS;
+ // if this access should use auto-precharge, then we are
+ // closing the row
+ if (auto_precharge) {
+ prechargeBank(bank, std::max(bank.freeAt, bank.tRASDoneAt) + tRP);
- // sample the relevant values when precharging
- bank.bytesAccessed = burstSize;
- bank.rowAccesses = 1;
+ DPRINTF(DRAM, "Auto-precharged bank: %d\n", dram_pkt->bankId);
+ }
- prechargeBank(bank, std::max(bank.freeAt, bank.tRASDoneAt) + tRP);
- DPRINTF(DRAM, "doDRAMAccess::bank.freeAt is %lld\n", bank.freeAt);
- } else
- panic("No page management policy chosen\n");
+ DPRINTF(DRAM, "doDRAMAccess::bank.freeAt is %lld\n", bank.freeAt);
// Update request parameters
dram_pkt->readyTime = curTick() + addDelay + accessLat + tBURST;
-
DPRINTF(DRAM, "Req %lld: curtick is %lld accessLat is %d " \
"readytime is %lld busbusyuntil is %lld. " \
"Scheduling at readyTime\n", dram_pkt->addr,