From 91cf58871efab95ca5303d8e06ae562c88073f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20M=C3=BCck?= Date: Tue, 15 Jun 2021 13:14:05 -0500 Subject: [PATCH] mem-ruby: support prefetcher in CHI protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use RubyPrefetcherProxy to support prefetchers in the CHI cache controller L1I/L1D/L2 prefechers can now be added by specifying a non-null prefetcher type when configuring a CHI_RNF. Related JIRA: https://gem5.atlassian.net/browse/GEM5-457 https://gem5.atlassian.net/browse/GEM5-1112 Additional authors: Tuan Ta Change-Id: I41dc637969acaab058b22a8c9c3931fa137eeace Signed-off-by: Tiago Mück --- configs/ruby/CHI_config.py | 33 ++++++++++++------- .../ruby/protocol/chi/CHI-cache-actions.sm | 13 ++++---- src/mem/ruby/protocol/chi/CHI-cache-funcs.sm | 33 ++++++++++++------- src/mem/ruby/protocol/chi/CHI-cache.sm | 9 +++++ 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/configs/ruby/CHI_config.py b/configs/ruby/CHI_config.py index 3cccfd0676..e14396183b 100644 --- a/configs/ruby/CHI_config.py +++ b/configs/ruby/CHI_config.py @@ -1,4 +1,4 @@ -# Copyright (c) 2021,2022 ARM Limited +# Copyright (c) 2021-2023 ARM Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -231,7 +231,8 @@ class CHI_L1Controller(CHI_Cache_Controller): super().__init__(ruby_system) self.sequencer = sequencer self.cache = cache - self.use_prefetcher = False + self.prefetcher = prefetcher + self.use_prefetcher = prefetcher != NULL self.send_evictions = True self.is_HN = False self.enable_DMT = False @@ -268,7 +269,8 @@ class CHI_L2Controller(CHI_Cache_Controller): super().__init__(ruby_system) self.sequencer = NULL self.cache = cache - self.use_prefetcher = False + self.prefetcher = prefetcher + self.use_prefetcher = prefetcher != NULL self.allow_SD = True self.is_HN = False self.enable_DMT = False @@ -304,7 +306,8 @@ class CHI_HNFController(CHI_Cache_Controller): super().__init__(ruby_system) self.sequencer = NULL self.cache = cache - self.use_prefetcher = False + self.prefetcher = prefetcher + self.use_prefetcher = prefetcher != NULL self.addr_ranges = addr_ranges self.allow_SD = True self.is_HN = True @@ -380,6 +383,7 @@ class CHI_DMAController(CHI_Cache_Controller): size = "128" assoc = 1 + self.prefetcher = NULL self.use_prefetcher = False self.cache = DummyCache() self.sequencer.dcache = NULL @@ -499,11 +503,16 @@ class CHI_RNF(CHI_Node): start_index_bit=self._block_size_bits, is_icache=False ) - # Placeholders for future prefetcher support - if l1Iprefetcher_type != None or l1Dprefetcher_type != None: - m5.fatal("Prefetching not supported yet") - l1i_pf = NULL - l1d_pf = NULL + # prefetcher wrappers + if l1Iprefetcher_type != None: + l1i_pf = l1Iprefetcher_type() + else: + l1i_pf = NULL + + if l1Dprefetcher_type != None: + l1d_pf = l1Dprefetcher_type() + else: + l1d_pf = NULL # cache controllers cpu.l1i = CHI_L1Controller( @@ -548,9 +557,11 @@ class CHI_RNF(CHI_Node): l2_cache = cache_type( start_index_bit=self._block_size_bits, is_icache=False ) + if pf_type != None: - m5.fatal("Prefetching not supported yet") - l2_pf = NULL + l2_pf = pf_type() + else: + l2_pf = NULL cpu.l2 = CHI_L2Controller(self._ruby_system, l2_cache, l2_pf) diff --git a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm index 4c9498423c..a827b8b1bb 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm @@ -3440,7 +3440,7 @@ action(Callback_ExpressPrefetchHit, desc="") { cache.profilePrefetchHit(); peek(reqRdyPort, CHIRequestMsg) { assert(in_msg.is_local_pf); - notifyPfComplete(in_msg.addr); + pfProxy.completePrefetch(in_msg.addr); } } @@ -3451,7 +3451,7 @@ action(Callback_Miss, desc="") { assert(is_valid(tbe)); if (tbe.dataValid && tbe.is_local_pf) { assert(use_prefetcher); - notifyPfComplete(tbe.addr); + pfProxy.completePrefetch(tbe.addr); } else if (tbe.dataValid && (tbe.reqType == CHIRequestType:Load)) { DPRINTF(RubySlicc, "Read data %s\n", tbe.dataBlk); @@ -3562,7 +3562,7 @@ action(Profile_Miss, desc="") { // FIXME: this dataBlk is likely to have stale data. This should be fixed // if our prefetcher uses cached data to make prefetch decisions. - notifyPfMiss(tbe.seqReq, is_read, tbe.dataBlk); + pfProxy.notifyPfMiss(tbe.seqReq, is_read, tbe.dataBlk); } } @@ -3586,7 +3586,7 @@ action(Profile_Hit, desc="") { } else { assert(isWriteReqType(tbe.reqType)); } - notifyPfHit(tbe.seqReq, is_read, tbe.dataBlk); + pfProxy.notifyPfHit(tbe.seqReq, is_read, tbe.dataBlk); cache_entry.HWPrefetched := false; } @@ -3600,10 +3600,11 @@ action(Profile_Fill, desc="") { cache_entry.HWPrefetched := tbe.is_local_pf || (tbe.is_remote_pf && (upstream_prefetch_trains_prefetcher == false)); + cache_entry.requestor := getRequestorID(tbe.seqReq); // Prefetchers that use this info require notifications from both // demand and pf fills (unlike notifyPfHit/notifyPfMiss) - notifyPfFill(tbe.seqReq, tbe.dataBlk, tbe.is_local_pf); + pfProxy.notifyPfFill(tbe.seqReq, tbe.dataBlk, tbe.is_local_pf); } } @@ -3617,7 +3618,7 @@ action(Profile_Eviction, desc="") { sequencer.evictionCallback(address); } if (use_prefetcher && is_valid(cache_entry)) { - notifyPfEvict(address, cache_entry.HWPrefetched); + pfProxy.notifyPfEvict(address, cache_entry.HWPrefetched, cache_entry.requestor); } } diff --git a/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm b/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm index ed8358fea4..113f4c4871 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm @@ -68,12 +68,6 @@ void outgoingTransactionEnd(Addr, bool, bool); Event curTransitionEvent(); State curTransitionNextState(); -// Placeholders for future prefetch support -void notifyPfHit(RequestPtr req, bool is_read, DataBlock blk) { } -void notifyPfMiss(RequestPtr req, bool is_read, DataBlock blk) { } -void notifyPfFill(RequestPtr req, DataBlock blk, bool from_pf) { } -void notifyPfEvict(Addr blkAddr, bool hwPrefetched) { } -void notifyPfComplete(Addr addr) { } //////////////////////////////////////////////////////////////////////////// // Interface functions required by SLICC @@ -307,7 +301,11 @@ bool fromSequencer(CHIRequestType reqType) { reqType == CHIRequestType:AtomicStore; } -bool inCache(Addr addr) { +void regProbePoints() { + pfProxy.regProbePoints(); +} + +bool inCache(Addr addr, bool is_secure) { CacheEntry entry := getCacheEntry(makeLineAddress(addr)); // NOTE: we consider data for the addr to be in cache if it exists in local, // upstream, or both caches. @@ -318,7 +316,16 @@ bool inCache(Addr addr) { } } -bool hasBeenPrefetched(Addr addr) { +bool hasBeenPrefetched(Addr addr, bool is_secure, RequestorID requestor) { + CacheEntry entry := getCacheEntry(makeLineAddress(addr)); + if (is_valid(entry)) { + return entry.HWPrefetched && (entry.requestor == requestor); + } else { + return false; + } +} + +bool hasBeenPrefetched(Addr addr, bool is_secure) { CacheEntry entry := getCacheEntry(makeLineAddress(addr)); if (is_valid(entry)) { return entry.HWPrefetched; @@ -327,12 +334,16 @@ bool hasBeenPrefetched(Addr addr) { } } -bool inMissQueue(Addr addr) { +bool inMissQueue(Addr addr, bool is_secure) { Addr line_addr := makeLineAddress(addr); TBE tbe := getCurrentActiveTBE(line_addr); return is_valid(tbe); } +bool coalesce() { + return false; +} + void notifyCoalesced(Addr addr, RubyRequestType type, RequestPtr req, DataBlock data_blk, bool was_miss) { DPRINTF(RubySlicc, "notifyCoalesced(addr=%#x, type=%s, was_miss=%d)\n", @@ -347,9 +358,9 @@ void notifyCoalesced(Addr addr, RubyRequestType type, RequestPtr req, (type == RubyRequestType:Load_Linked) || (type == RubyRequestType:IFETCH); if (was_miss) { - notifyPfMiss(req, is_read, data_blk); + pfProxy.notifyPfMiss(req, is_read, data_blk); } else { - notifyPfHit(req, is_read, data_blk); + pfProxy.notifyPfHit(req, is_read, data_blk); } } } diff --git a/src/mem/ruby/protocol/chi/CHI-cache.sm b/src/mem/ruby/protocol/chi/CHI-cache.sm index f806488b45..62fb2231ff 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache.sm @@ -46,6 +46,10 @@ machine(MachineType:Cache, "Cache coherency protocol") : // happen in parallel. The cache tag latency is used for both cases. CacheMemory * cache; + // Prefetcher to insert prefetch requests + // null if the cache does not support prefetching + prefetch::Base * prefetcher; + // Additional pipeline latency modeling for the different request types // When defined, these are applied after the initial tag array read and // sending necessary snoops. @@ -568,6 +572,7 @@ machine(MachineType:Cache, "Cache coherency protocol") : State state, desc="SLICC line state"; DataBlock DataBlk, desc="data for the block"; bool HWPrefetched, default="false", desc="Set if this cache entry was prefetched"; + RequestorID requestor, desc="First requestor to fill this block"; } // Directory entry @@ -812,6 +817,10 @@ machine(MachineType:Cache, "Cache coherency protocol") : TBETable dvmSnpTBEs, template="", constructor="m_number_of_DVM_snoop_TBEs"; TBEStorage storDvmSnpTBEs, constructor="this, m_number_of_DVM_snoop_TBEs"; + // Interface to prefetchers + RubyPrefetcherProxy pfProxy, constructor="this, m_prefetcher_ptr, m_prefetchQueue_ptr"; + + // DVM data // Queue of non-sync operations that haven't been Comp-d yet. // Before a Sync operation can start, this queue must be emptied