mem-ruby: MESI_Three_Level LL/SC improvements
authorTimothy Hayes <timothy.hayes@arm.com>
Mon, 27 Apr 2020 14:04:09 +0000 (15:04 +0100)
committerPouya Fotouhi <pfotouhi@ucdavis.edu>
Sat, 2 May 2020 06:49:17 +0000 (06:49 +0000)
This patch fixes the MESI_Three_Level protocols so that it correctly
informers the Ruby sequencer when a line eviction occurs. Furthermore,
the patch allows the protocol to recognize the 'Store_Conditional'
RubyRequestType and shortcuts this operation if the monitored line
has been cleared from the address monitor. This prevents certain
livelock behaviour in which a line could ping-pong between competing
cores.

The patch establishes a new C/C++ preprocessor definition which allows
the Sequencer to send the 'Store_Conditional' RubyRequestType to
MESI_Three_Level instead of 'ST'. This is a temporary measure until
the other protocols explicitely recognize 'Store_Conditional'.

Change-Id: I27ae041ab0e015a4f54f20df666f9c4873c7583d
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/28328
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu>
Tested-by: kokoro <noreply+kokoro@google.com>
src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm
src/mem/ruby/system/SConscript
src/mem/ruby/system/Sequencer.cc

index b74a7276a4e22d696927fc0c4f2de03b871e7787..14fb07adf793f471cf93174b201102d70f85a825 100644 (file)
@@ -121,6 +121,8 @@ machine(MachineType:L0Cache, "MESI Directory L0 Cache")
     Ack,        desc="Ack for processor";
 
     WB_Ack,        desc="Ack for replacement";
+
+    Failed_SC,        desc="Store conditional request that will fail";
   }
 
   // TYPES
@@ -257,7 +259,8 @@ machine(MachineType:L0Cache, "MESI Directory L0 Cache")
       return Event:Load;
     } else if (type == RubyRequestType:IFETCH) {
       return Event:Ifetch;
-    } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)) {
+    } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)
+               || (type == RubyRequestType:Store_Conditional)) {
       return Event:Store;
     } else {
       error("Invalid RubyRequestType");
@@ -349,36 +352,51 @@ machine(MachineType:L0Cache, "MESI Directory L0 Cache")
             }
           }
         } else {
-
           // *** DATA ACCESS ***
           Entry Dcache_entry := getDCacheEntry(in_msg.LineAddress);
+
+          // early out for failed store conditionals
+
+          if (in_msg.Type == RubyRequestType:Store_Conditional) {
+              if (!sequencer.llscCheckMonitor(in_msg.LineAddress)) {
+                trigger(Event:Failed_SC, in_msg.LineAddress,
+                        Dcache_entry, TBEs[in_msg.LineAddress]);
+            }
+          }
+
           if (is_valid(Dcache_entry)) {
             // The tag matches for the L0, so the L0 ask the L1 for it
             trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress,
                     Dcache_entry, TBEs[in_msg.LineAddress]);
           } else {
-
-            // Check to see if it is in the OTHER L0
-            Entry Icache_entry := getICacheEntry(in_msg.LineAddress);
-            if (is_valid(Icache_entry)) {
-              // The block is in the wrong L0, put the request on the queue to the private L1
-              trigger(Event:L0_Replacement, in_msg.LineAddress,
-                      Icache_entry, TBEs[in_msg.LineAddress]);
-            }
-
-            if (Dcache.cacheAvail(in_msg.LineAddress)) {
-              // L1 does't have the line, but we have space for it
-              // in the L0 let's see if the L1 has it
-              trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress,
-                      Dcache_entry, TBEs[in_msg.LineAddress]);
+            // if the request is not valid, the store conditional will fail
+            if (in_msg.Type == RubyRequestType:Store_Conditional) {
+                // if the line is not valid, it can't be locked
+                trigger(Event:Failed_SC, in_msg.LineAddress,
+                        Dcache_entry, TBEs[in_msg.LineAddress]);
             } else {
-              // No room in the L1, so we need to make room in the L0
-              // Check if the line we want to evict is not locked
-              Addr addr := Dcache.cacheProbe(in_msg.LineAddress);
-              check_on_cache_probe(mandatoryQueue_in, addr);
-              trigger(Event:L0_Replacement, addr,
-                      getDCacheEntry(addr),
-                      TBEs[addr]);
+              // Check to see if it is in the OTHER L0
+              Entry Icache_entry := getICacheEntry(in_msg.LineAddress);
+              if (is_valid(Icache_entry)) {
+                // The block is in the wrong L0, put the request on the queue to the private L1
+                trigger(Event:L0_Replacement, in_msg.LineAddress,
+                        Icache_entry, TBEs[in_msg.LineAddress]);
+              }
+
+              if (Dcache.cacheAvail(in_msg.LineAddress)) {
+                // L1 does't have the line, but we have space for it
+                // in the L0 let's see if the L1 has it
+                trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress,
+                        Dcache_entry, TBEs[in_msg.LineAddress]);
+              } else {
+                // No room in the L1, so we need to make room in the L0
+                // Check if the line we want to evict is not locked
+                Addr addr := Dcache.cacheProbe(in_msg.LineAddress);
+                check_on_cache_probe(mandatoryQueue_in, addr);
+                trigger(Event:L0_Replacement, addr,
+                        getDCacheEntry(addr),
+                        TBEs[addr]);
+              }
             }
           }
         }
@@ -629,6 +647,13 @@ machine(MachineType:L0Cache, "MESI Directory L0 Cache")
         ++Dcache.demand_hits;
   }
 
+  // store conditionals
+
+  action(hhc_storec_fail, "\hc",
+         desc="Notify sequencer that store conditional failed") {
+    sequencer.writeCallbackScFail(address, cache_entry.DataBlk);
+  }
+
   //*****************************************************
   // TRANSITIONS
   //*****************************************************
@@ -664,11 +689,13 @@ machine(MachineType:L0Cache, "MESI Directory L0 Cache")
   }
 
   transition({I, IS, IM, Inst_IS}, {InvOwn, InvElse}) {
+    forward_eviction_to_cpu;
     fi_sendInvAck;
     l_popRequestQueue;
   }
 
   transition(SM, {InvOwn, InvElse}, IM) {
+    forward_eviction_to_cpu;
     fi_sendInvAck;
     l_popRequestQueue;
   }
@@ -768,6 +795,7 @@ machine(MachineType:L0Cache, "MESI Directory L0 Cache")
 
   transition(IS, Data_Stale, I) {
     u_writeDataToCache;
+    forward_eviction_to_cpu;
     hx_load_hit;
     s_deallocateTBE;
     ff_deallocateCacheBlock;
@@ -807,4 +835,12 @@ machine(MachineType:L0Cache, "MESI Directory L0 Cache")
     o_popIncomingResponseQueue;
     kd_wakeUpDependents;
   }
+
+  // store conditionals
+
+  transition({I,S,E,M}, Failed_SC) {
+    // IS,IM,SM don't handle store conditionals
+    hhc_storec_fail;
+    k_popMandatoryQueue;
+  }
 }
index d196b68abe5fe3a5487187bb1872da145f9a97c1..7496971c829fbf2f68252e9279cce25b7f0215d6 100644 (file)
@@ -1,5 +1,17 @@
 # -*- mode:python -*-
 
+# Copyright (c) 2020 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder.  You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
 # Copyright (c) 2009 The Hewlett-Packard Development Company
 # All rights reserved.
 #
@@ -31,6 +43,8 @@ Import('*')
 if env['PROTOCOL'] == 'None':
     Return()
 
+env.Append(CPPDEFINES=['PROTOCOL_' + env['PROTOCOL']])
+
 if env['BUILD_GPU']:
     SimObject('GPUCoalescer.py')
 SimObject('RubySystem.py')
index 0287e13013c5b2989629b97b53b40d8c110ac8c7..de7941a498cbfd1d7c6e6a161999e22eb350a85a 100644 (file)
@@ -590,7 +590,11 @@ Sequencer::makeRequest(PacketPtr pkt)
         if (pkt->isWrite()) {
             DPRINTF(RubySequencer, "Issuing SC\n");
             primary_type = RubyRequestType_Store_Conditional;
+#ifdef PROTOCOL_MESI_Three_Level
+            secondary_type = RubyRequestType_Store_Conditional;
+#else
             secondary_type = RubyRequestType_ST;
+#endif
         } else {
             DPRINTF(RubySequencer, "Issuing LL\n");
             assert(pkt->isRead());