ruby: call setMRU from L1 controllers, not from sequencer
authorNilay Vaish <nilay@cs.wisc.edu>
Sat, 15 Aug 2015 00:28:43 +0000 (19:28 -0500)
committerNilay Vaish <nilay@cs.wisc.edu>
Sat, 15 Aug 2015 00:28:43 +0000 (19:28 -0500)
Currently the sequencer calls the function setMRU that updates the replacement
policy structures with the first level caches.  While functionally this is
correct, the problem is that this requires calling findTagInSet() which is an
expensive function.  This patch removes the calls to setMRU from the sequencer.
All controllers should now update the replacement policy on their own.

The set and the way index for a given cache entry can be found within the
AbstractCacheEntry structure. Use these indicies to update the replacement
policy structures.

src/mem/protocol/MESI_Three_Level-L0cache.sm
src/mem/protocol/MESI_Two_Level-L1cache.sm
src/mem/protocol/MI_example-cache.sm
src/mem/protocol/MOESI_CMP_directory-L1cache.sm
src/mem/protocol/MOESI_CMP_token-L1cache.sm
src/mem/protocol/MOESI_hammer-cache.sm
src/mem/protocol/RubySlicc_Types.sm
src/mem/ruby/structures/CacheMemory.cc
src/mem/ruby/structures/CacheMemory.hh
src/mem/ruby/system/Sequencer.cc

index 4299f0db481cce7d9406dfc72f85903ff183b003..fb9e762daff66e59f4496508fe1ca2fc278cfa99 100644 (file)
@@ -459,21 +459,38 @@ machine(L0Cache, "MESI Directory L0 Cache")
     }
   }
 
-  action(h_load_hit, "h", desc="If not prefetch, notify sequencer the load completed.") {
+  action(h_load_hit, "hd", desc="If not prefetch, notify sequencer the load completed.") {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    Dcache.setMRU(cache_entry);
     sequencer.readCallback(address, cache_entry.DataBlk);
   }
 
-  action(hx_load_hit, "hx", desc="If not prefetch, notify sequencer the load completed.") {
+  action(h_ifetch_hit, "hi", desc="If not prefetch, notify sequencer the ifetch completed.") {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    Icache.setMRU(cache_entry);
+    sequencer.readCallback(address, cache_entry.DataBlk);
+  }
+
+  action(hx_load_hit, "hxd", desc="notify sequencer the load completed.") {
+    assert(is_valid(cache_entry));
+    DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    Dcache.setMRU(cache_entry);
+    sequencer.readCallback(address, cache_entry.DataBlk, true);
+  }
+
+  action(hx_ifetch_hit, "hxi", desc="notify sequencer the ifetch completed.") {
+    assert(is_valid(cache_entry));
+    DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    Icache.setMRU(cache_entry);
     sequencer.readCallback(address, cache_entry.DataBlk, true);
   }
 
   action(hh_store_hit, "\h", desc="If not prefetch, notify sequencer that store completed.") {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    Dcache.setMRU(cache_entry);
     sequencer.writeCallback(address, cache_entry.DataBlk);
     cache_entry.Dirty := true;
   }
@@ -481,6 +498,7 @@ machine(L0Cache, "MESI Directory L0 Cache")
   action(hhx_store_hit, "\hx", desc="If not prefetch, notify sequencer that store completed.") {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    Dcache.setMRU(cache_entry);
     sequencer.writeCallback(address, cache_entry.DataBlk, true);
     cache_entry.Dirty := true;
   }
@@ -625,7 +643,7 @@ machine(L0Cache, "MESI Directory L0 Cache")
   }
 
   transition({S,E,M}, Ifetch) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileInstHit;
     k_popMandatoryQueue;
   }
@@ -712,7 +730,7 @@ machine(L0Cache, "MESI Directory L0 Cache")
 
   transition(Inst_IS, Data, S) {
     u_writeInstToCache;
-    hx_load_hit;
+    hx_ifetch_hit;
     s_deallocateTBE;
     o_popIncomingResponseQueue;
     kd_wakeUpDependents;
@@ -720,7 +738,7 @@ machine(L0Cache, "MESI Directory L0 Cache")
 
   transition(Inst_IS, Data_Exclusive, E) {
     u_writeInstToCache;
-    hx_load_hit;
+    hx_ifetch_hit;
     s_deallocateTBE;
     o_popIncomingResponseQueue;
     kd_wakeUpDependents;
index 00c390c4a3c72cc753fd7e544a88e1ea600d143f..f4978050dc4a56e2b5798924c8e9d5f86c6070b5 100644 (file)
@@ -809,36 +809,47 @@ machine(L1Cache, "MESI Directory L1 Cache CMP")
     sequencer.invalidateSC(address);
   }
 
-  action(h_load_hit, "h",
-         desc="If not prefetch, notify sequencer the load completed.")
+  action(h_load_hit, "hd",
+         desc="Notify sequencer the load completed.")
   {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    L1Dcache.setMRU(cache_entry);
     sequencer.readCallback(address, cache_entry.DataBlk);
   }
 
-  action(hx_load_hit, "hx",
-         desc="If not prefetch, notify sequencer the load completed.")
+  action(h_ifetch_hit, "hi", desc="Notify sequencer the instruction fetch completed.")
   {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    L1Icache.setMRU(cache_entry);
+    sequencer.readCallback(address, cache_entry.DataBlk);
+  }
+
+  action(hx_load_hit, "hx", desc="Notify sequencer the load completed.")
+  {
+    assert(is_valid(cache_entry));
+    DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    L1Icache.setMRU(address);
+    L1Dcache.setMRU(address);
     sequencer.readCallback(address, cache_entry.DataBlk, true);
   }
 
-  action(hh_store_hit, "\h",
-         desc="If not prefetch, notify sequencer that store completed.")
+  action(hh_store_hit, "\h", desc="Notify sequencer that store completed.")
   {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    L1Dcache.setMRU(cache_entry);
     sequencer.writeCallback(address, cache_entry.DataBlk);
     cache_entry.Dirty := true;
   }
 
-  action(hhx_store_hit, "\hx",
-         desc="If not prefetch, notify sequencer that store completed.")
+  action(hhx_store_hit, "\hx", desc="Notify sequencer that store completed.")
   {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    L1Icache.setMRU(address);
+    L1Dcache.setMRU(address);
     sequencer.writeCallback(address, cache_entry.DataBlk, true);
     cache_entry.Dirty := true;
   }
@@ -1080,7 +1091,7 @@ machine(L1Cache, "MESI Directory L1 Cache CMP")
   }
 
   transition({S,E,M}, Ifetch) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileInstHit;
     k_popMandatoryQueue;
   }
index 4a1d6e946ccb2f00563cdca2963b00f7caf5aac4..d247ce663ab20616ec16fb37bca2c25a47fab245 100644 (file)
@@ -353,6 +353,7 @@ machine(L1Cache, "MI Example L1 Cache")
   action(r_load_hit, "r", desc="Notify sequencer the load completed.") {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk);
+    cacheMemory.setMRU(cache_entry);
     sequencer.readCallback(address, cache_entry.DataBlk, false);
   }
 
@@ -360,6 +361,7 @@ machine(L1Cache, "MI Example L1 Cache")
     peek(responseNetwork_in, ResponseMsg) {
       assert(is_valid(cache_entry));
       DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk);
+      cacheMemory.setMRU(cache_entry);
       sequencer.readCallback(address, cache_entry.DataBlk, true,
                              machineIDToMachineType(in_msg.Sender));
     }
@@ -368,6 +370,7 @@ machine(L1Cache, "MI Example L1 Cache")
   action(s_store_hit, "s", desc="Notify sequencer that store completed.") {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk);
+    cacheMemory.setMRU(cache_entry);
     sequencer.writeCallback(address, cache_entry.DataBlk, false);
   }
 
@@ -375,6 +378,7 @@ machine(L1Cache, "MI Example L1 Cache")
     peek(responseNetwork_in, ResponseMsg) {
       assert(is_valid(cache_entry));
       DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk);
+      cacheMemory.setMRU(cache_entry);
       sequencer.writeCallback(address, cache_entry.DataBlk, true,
                               machineIDToMachineType(in_msg.Sender));
     }
index 17a39a210f8426cc37e8d1bca0e3a556806a3318..7a8f35333c5d759c5cb1cccae19cf185e05b13a8 100644 (file)
@@ -635,21 +635,32 @@ machine(L1Cache, "Directory protocol")
     }
   }
 
-  action(h_load_hit, "h", desc="Notify sequencer the load completed.") {
+  action(h_load_hit, "hd", desc="Notify sequencer the load completed.") {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    L1Dcache.setMRU(cache_entry);
+    sequencer.readCallback(address, cache_entry.DataBlk);
+  }
+
+  action(h_ifetch_hit, "hi", desc="Notify the sequencer about ifetch completion.") {
+    assert(is_valid(cache_entry));
+    DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    L1Icache.setMRU(cache_entry);
     sequencer.readCallback(address, cache_entry.DataBlk);
   }
 
   action(hx_load_hit, "hx", desc="Notify sequencer the load completed.") {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    L1Icache.setMRU(address);
+    L1Dcache.setMRU(address);
     sequencer.readCallback(address, cache_entry.DataBlk, true);
   }
 
   action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    L1Dcache.setMRU(cache_entry);
     sequencer.writeCallback(address, cache_entry.DataBlk);
     cache_entry.Dirty := true;
   }
@@ -657,6 +668,8 @@ machine(L1Cache, "Directory protocol")
   action(xx_store_hit, "\xx", desc="Notify sequencer that store completed.") {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    L1Icache.setMRU(address);
+    L1Dcache.setMRU(address);
     sequencer.writeCallback(address, cache_entry.DataBlk, true);
     cache_entry.Dirty := true;
   }
@@ -964,7 +977,7 @@ machine(L1Cache, "Directory protocol")
   }
 
   transition({S, SM, O, OM, MM, MM_W, M, M_W}, Ifetch) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileInstHit;
     k_popMandatoryQueue;
   }
index 067adfc542db70419ae030e3b284a84ee08dd2c1..1d47f1c8a4e571e16f177e834d12e1137fdbbb88 100644 (file)
@@ -1284,12 +1284,22 @@ machine(L1Cache, "Token protocol")
     }
   }
 
+  action(h_load_hit, "hd", desc="Notify sequencer the load completed.") {
+    assert(is_valid(cache_entry));
+    DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n",
+            address, cache_entry.DataBlk);
 
-  action(h_load_hit, "h", desc="Notify sequencer the load completed.") {
+    L1Dcache.setMRU(cache_entry);
+    sequencer.readCallback(address, cache_entry.DataBlk, false,
+                           MachineType:L1Cache);
+  }
+
+  action(h_ifetch_hit, "hi", desc="Notify sequencer the load completed.") {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n",
             address, cache_entry.DataBlk);
 
+    L1Icache.setMRU(cache_entry);
     sequencer.readCallback(address, cache_entry.DataBlk, false,
                            MachineType:L1Cache);
   }
@@ -1299,6 +1309,8 @@ machine(L1Cache, "Token protocol")
     DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n",
             address, cache_entry.DataBlk);
     peek(responseNetwork_in, ResponseMsg) {
+      L1Icache.setMRU(address);
+      L1Dcache.setMRU(address);
       sequencer.readCallback(address, cache_entry.DataBlk,
                              isExternalHit(address, in_msg.Sender),
                              machineIDToMachineType(in_msg.Sender));
@@ -1310,6 +1322,7 @@ machine(L1Cache, "Token protocol")
     DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n",
             address, cache_entry.DataBlk);
 
+    L1Dcache.setMRU(cache_entry);
     sequencer.writeCallback(address, cache_entry.DataBlk, false,
                             MachineType:L1Cache);
     cache_entry.Dirty := true;
@@ -1321,6 +1334,8 @@ machine(L1Cache, "Token protocol")
     DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n",
             address, cache_entry.DataBlk);
     peek(responseNetwork_in, ResponseMsg) {
+      L1Icache.setMRU(address);
+      L1Dcache.setMRU(address);
       sequencer.writeCallback(address, cache_entry.DataBlk,
                               isExternalHit(address, in_msg.Sender),
                               machineIDToMachineType(in_msg.Sender));
@@ -1702,7 +1717,7 @@ machine(L1Cache, "Token protocol")
   }
 
   transition({S, SM, S_L, SM_L}, Ifetch) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileInstHit;
     k_popMandatoryQueue;
   }
@@ -1784,7 +1799,7 @@ machine(L1Cache, "Token protocol")
 
   // Transitions from Owned
   transition({O, OM}, Ifetch) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileInstHit;
     k_popMandatoryQueue;
   }
@@ -1874,7 +1889,7 @@ machine(L1Cache, "Token protocol")
 
   // Transitions from Modified
   transition({MM, MM_W}, Ifetch) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileInstHit;
     k_popMandatoryQueue;
   }
@@ -1949,7 +1964,7 @@ machine(L1Cache, "Token protocol")
 
   // Transitions from Dirty Exclusive
   transition({M, M_W}, Ifetch) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileInstHit;
     k_popMandatoryQueue;
   }
index 0b7acb7015ea7c0d9cb44162a5dc160cfa575cd3..269e47dfda7c6bc10f5df47af2ef0be45f70a5e7 100644 (file)
@@ -857,9 +857,18 @@ machine({L1Cache, L2Cache}, "AMD Hammer-like protocol")
     }
   }
 
-  action(h_load_hit, "h", desc="Notify sequencer the load completed.") {
+  action(h_load_hit, "hd", desc="Notify sequencer the load completed.") {
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    L1Dcache.setMRU(cache_entry);
+    sequencer.readCallback(address, cache_entry.DataBlk, false,
+                           testAndClearLocalHit(cache_entry));
+  }
+
+  action(h_ifetch_hit, "hi", desc="Notify sequencer the ifetch completed.") {
+    assert(is_valid(cache_entry));
+    DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
+    L1Icache.setMRU(cache_entry);
     sequencer.readCallback(address, cache_entry.DataBlk, false,
                            testAndClearLocalHit(cache_entry));
   }
@@ -869,7 +878,8 @@ machine({L1Cache, L2Cache}, "AMD Hammer-like protocol")
     assert(is_valid(tbe));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
     peek(responseToCache_in, ResponseMsg) {
-
+      L1Icache.setMRU(address);
+      L1Dcache.setMRU(address);
       sequencer.readCallback(address, cache_entry.DataBlk, true,
                  machineIDToMachineType(in_msg.Sender), tbe.InitialRequestTime,
                  tbe.ForwardRequestTime, tbe.FirstResponseTime);
@@ -880,6 +890,7 @@ machine({L1Cache, L2Cache}, "AMD Hammer-like protocol")
     assert(is_valid(cache_entry));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
     peek(mandatoryQueue_in, RubyRequest) {
+      L1Dcache.setMRU(cache_entry);
       sequencer.writeCallback(address, cache_entry.DataBlk, false,
                               testAndClearLocalHit(cache_entry));
 
@@ -901,7 +912,8 @@ machine({L1Cache, L2Cache}, "AMD Hammer-like protocol")
     assert(is_valid(tbe));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
     peek(responseToCache_in, ResponseMsg) {
-
+      L1Icache.setMRU(address);
+      L1Dcache.setMRU(address);
       sequencer.writeCallback(address, cache_entry.DataBlk, true,
               machineIDToMachineType(in_msg.Sender), tbe.InitialRequestTime,
               tbe.ForwardRequestTime, tbe.FirstResponseTime);
@@ -914,7 +926,8 @@ machine({L1Cache, L2Cache}, "AMD Hammer-like protocol")
     assert(is_valid(cache_entry));
     assert(is_valid(tbe));
     DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
-
+    L1Icache.setMRU(address);
+    L1Dcache.setMRU(address);
     sequencer.writeCallback(address, cache_entry.DataBlk, true,
             machineIDToMachineType(tbe.LastResponder), tbe.InitialRequestTime,
             tbe.ForwardRequestTime, tbe.FirstResponseTime);
@@ -1508,7 +1521,7 @@ machine({L1Cache, L2Cache}, "AMD Hammer-like protocol")
   }
 
   transition({S, SM, ISM}, Ifetch) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileL1InstHit;
     k_popMandatoryQueue;
   }
@@ -1522,7 +1535,7 @@ machine({L1Cache, L2Cache}, "AMD Hammer-like protocol")
   }
 
   transition(SR, Ifetch, S) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileL1InstMiss;
     uu_profileL2Hit;
     k_popMandatoryQueue;
@@ -1570,7 +1583,7 @@ machine({L1Cache, L2Cache}, "AMD Hammer-like protocol")
   }
 
   transition({O, OM, SS, MM_W, M_W}, {Ifetch}) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileL1InstHit;
     k_popMandatoryQueue;
   }
@@ -1584,7 +1597,7 @@ machine({L1Cache, L2Cache}, "AMD Hammer-like protocol")
   }
 
   transition(OR, Ifetch, O) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileL1InstMiss;
     uu_profileL2Hit;
     k_popMandatoryQueue;
@@ -1635,7 +1648,7 @@ machine({L1Cache, L2Cache}, "AMD Hammer-like protocol")
 
   // Transitions from Modified
   transition({MM, M}, {Ifetch}) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileL1InstHit;
     k_popMandatoryQueue;
   }
@@ -1661,7 +1674,7 @@ machine({L1Cache, L2Cache}, "AMD Hammer-like protocol")
   }
 
   transition(MMR, Ifetch, MM) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileL1InstMiss;
     uu_profileL2Hit;
     k_popMandatoryQueue;
@@ -1742,7 +1755,7 @@ machine({L1Cache, L2Cache}, "AMD Hammer-like protocol")
   }
 
   transition(MR, Ifetch, M) {
-    h_load_hit;
+    h_ifetch_hit;
     uu_profileL1InstMiss;
     uu_profileL2Hit;
     k_popMandatoryQueue;
index d032adfd8968e05ca9a91113b20e82410d32f0eb..f464b3c7d747a21f8816ed17f2ea0becd265104f 100644 (file)
@@ -156,6 +156,7 @@ structure (CacheMemory, external = "yes") {
   Cycles getTagLatency();
   Cycles getDataLatency();
   void setMRU(Addr);
+  void setMRU(AbstractCacheEntry);
   void recordRequestType(CacheRequestType, Addr);
   bool checkResourceAvailable(CacheResourceType, Addr);
 
index ab26477597da4878e2925ba9b3ec9e702491d7b3..931f58a8ef686b111f1d829c5b43920c169026b4 100644 (file)
@@ -343,6 +343,14 @@ CacheMemory::setMRU(Addr address)
         m_replacementPolicy_ptr->touch(cacheSet, loc, curTick());
 }
 
+void
+CacheMemory::setMRU(const AbstractCacheEntry *e)
+{
+    uint32_t cacheSet = e->getSetIndex();
+    uint32_t loc = e->getWayIndex();
+    m_replacementPolicy_ptr->touch(cacheSet, loc, curTick());
+}
+
 void
 CacheMemory::recordCacheContents(int cntrl, CacheRecorder* tr) const
 {
index 1af4469508ca12a2cc2a375e08b6075e677a33ca..7ce674e61a6473e2f780ac97a7a18b3bad0abd6d 100644 (file)
@@ -106,6 +106,8 @@ class CacheMemory : public SimObject
 
     // Set this address to most recently used
     void setMRU(Addr address);
+    // Set this entry to most recently used
+    void setMRU(const AbstractCacheEntry *e);
 
     // Functions for locking and unlocking cache lines corresponding to the
     // provided address.  These are required for supporting atomic memory
index b21c70743fbc762ccd5d671d8bb3fdc7bfc72d66..740db7d8ded9ad84d1ac7638ab7d28bde9729d65 100644 (file)
@@ -496,19 +496,15 @@ Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data,
                        const Cycles forwardRequestTime,
                        const Cycles firstResponseTime)
 {
+    warn_once("Replacement policy updates recently became the responsibility "
+              "of SLICC state machines. Make sure to setMRU() near callbacks "
+              "in .sm files!");
+
     PacketPtr pkt = srequest->pkt;
     Addr request_address(pkt->getAddr());
-    Addr request_line_address = makeLineAddress(pkt->getAddr());
     RubyRequestType type = srequest->m_type;
     Cycles issued_time = srequest->issue_time;
 
-    // Set this cache entry to the most recently used
-    if (type == RubyRequestType_IFETCH) {
-        m_instCache_ptr->setMRU(request_line_address);
-    } else {
-        m_dataCache_ptr->setMRU(request_line_address);
-    }
-
     assert(curCycle() >= issued_time);
     Cycles total_latency = curCycle() - issued_time;