From e61f10740bf17437c3d771593e9e1830aa90d1d2 Mon Sep 17 00:00:00 2001 From: Timothy Hayes Date: Mon, 27 Apr 2020 15:04:09 +0100 Subject: [PATCH] mem-ruby: MESI_Three_Level LL/SC improvements 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 Maintainer: Bobby R. Bruce Tested-by: kokoro --- .../ruby/protocol/MESI_Three_Level-L0cache.sm | 82 +++++++++++++------ src/mem/ruby/system/SConscript | 14 ++++ src/mem/ruby/system/Sequencer.cc | 4 + 3 files changed, 77 insertions(+), 23 deletions(-) diff --git a/src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm b/src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm index b74a7276a..14fb07adf 100644 --- a/src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm +++ b/src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm @@ -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; + } } diff --git a/src/mem/ruby/system/SConscript b/src/mem/ruby/system/SConscript index d196b68ab..7496971c8 100644 --- a/src/mem/ruby/system/SConscript +++ b/src/mem/ruby/system/SConscript @@ -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') diff --git a/src/mem/ruby/system/Sequencer.cc b/src/mem/ruby/system/Sequencer.cc index 0287e1301..de7941a49 100644 --- a/src/mem/ruby/system/Sequencer.cc +++ b/src/mem/ruby/system/Sequencer.cc @@ -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()); -- 2.30.2