mem: Merge DRAM page-management calculations
authorAndreas Hansson <andreas.hansson@arm.com>
Fri, 9 May 2014 22:58:48 +0000 (18:58 -0400)
committerAndreas Hansson <andreas.hansson@arm.com>
Fri, 9 May 2014 22:58:48 +0000 (18:58 -0400)
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.

src/mem/dram_ctrl.cc

index 3774220b5e71055645bc7a26613b5b7e81960541..7062390e86c58a131e182fb3a214dccb1b2d9b65 100644 (file)
@@ -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,