gem5 v24.0.0.0
Loading...
Searching...
No Matches
snoop_filter.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013-2017,2019 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
43#include "mem/snoop_filter.hh"
44
45#include "base/logging.hh"
46#include "base/trace.hh"
47#include "debug/SnoopFilter.hh"
48#include "sim/system.hh"
49
50namespace gem5
51{
52
54
55void
56SnoopFilter::eraseIfNullEntry(SnoopFilterCache::iterator& sf_it)
57{
58 SnoopItem& sf_item = sf_it->second;
59 if ((sf_item.requested | sf_item.holder).none()) {
60 cachedLocations.erase(sf_it);
61 DPRINTF(SnoopFilter, "%s: Removed SF entry.\n",
62 __func__);
63 }
64}
65
68 cpu_side_port)
69{
70 DPRINTF(SnoopFilter, "%s: src %s packet %s\n", __func__,
71 cpu_side_port.name(), cpkt->print());
72
73 // check if the packet came from a cache
74 bool allocate = !cpkt->req->isUncacheable() && cpu_side_port.isSnooping()
75 && cpkt->fromCache();
76 Addr line_addr = cpkt->getBlockAddr(linesize);
77 if (cpkt->isSecure()) {
78 line_addr |= LineSecure;
79 }
80 SnoopMask req_port = portToMask(cpu_side_port);
81 reqLookupResult.it = cachedLocations.find(line_addr);
82 bool is_hit = (reqLookupResult.it != cachedLocations.end());
83
84 // If the snoop filter has no entry, and we should not allocate,
85 // do not create a new snoop filter entry, simply return a NULL
86 // portlist.
87 if (!is_hit && !allocate)
89
90 // If no hit in snoop filter create a new element and update iterator
91 if (!is_hit) {
93 cachedLocations.emplace(line_addr, SnoopItem()).first;
94 }
95 SnoopItem& sf_item = reqLookupResult.it->second;
96 SnoopMask interested = sf_item.holder | sf_item.requested;
97
98 // Store unmodified value of snoop filter item in temp storage in
99 // case we need to revert because of a send retry in
100 // updateRequest.
101 reqLookupResult.retryItem = sf_item;
102
104 if (is_hit) {
105 if (interested.count() == 1)
107 else
109 }
110
111 DPRINTF(SnoopFilter, "%s: SF value %x.%x\n",
112 __func__, sf_item.requested, sf_item.holder);
113
114 // If we are not allocating, we are done
115 if (!allocate)
116 return snoopSelected(maskToPortList(interested & ~req_port),
118
119 if (cpkt->needsResponse()) {
120 if (!cpkt->cacheResponding()) {
121 // Max one request per address per port
122 panic_if((sf_item.requested & req_port).any(),
123 "double request :( SF value %x.%x\n",
124 sf_item.requested, sf_item.holder);
125
126 // Mark in-flight requests to distinguish later on
127 sf_item.requested |= req_port;
128 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
129 __func__, sf_item.requested, sf_item.holder);
130 } else {
131 // NOTE: The memInhibit might have been asserted by a cache closer
132 // to the CPU, already -> the response will not be seen by this
133 // filter -> we do not need to keep the in-flight request, but make
134 // sure that we know that that cluster has a copy
135 panic_if((sf_item.holder & req_port).none(),
136 "Need to hold the value!");
138 "%s: not marking request. SF value %x.%x\n",
139 __func__, sf_item.requested, sf_item.holder);
140 }
141 } else { // if (!cpkt->needsResponse())
142 assert(cpkt->isEviction());
143 // make sure that the sender actually had the line
144 panic_if((sf_item.holder & req_port).none(), "requestor %x is not a " \
145 "holder :( SF value %x.%x\n", req_port,
146 sf_item.requested, sf_item.holder);
147 // CleanEvicts and Writebacks -> the sender and all caches above
148 // it may not have the line anymore.
149 if (!cpkt->isBlockCached()) {
150 sf_item.holder &= ~req_port;
151 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
152 __func__, sf_item.requested, sf_item.holder);
153 }
154 }
155
156 return snoopSelected(maskToPortList(interested & ~req_port), lookupLatency);
157}
158
159void
160SnoopFilter::finishRequest(bool will_retry, Addr addr, bool is_secure)
161{
162 if (reqLookupResult.it != cachedLocations.end()) {
163 // since we rely on the caller, do a basic check to ensure
164 // that finishRequest is being called following lookupRequest
165 assert(reqLookupResult.it->first == \
166 (is_secure ? ((addr & ~(Addr(linesize - 1))) | LineSecure) : \
167 (addr & ~(Addr(linesize - 1)))));
168 if (will_retry) {
170 // Undo any changes made in lookupRequest to the snoop filter
171 // entry if the request will come again. retryItem holds
172 // the previous value of the snoopfilter entry.
173 reqLookupResult.it->second = retry_item;
174
175 DPRINTF(SnoopFilter, "%s: restored SF value %x.%x\n",
176 __func__, retry_item.requested, retry_item.holder);
177 }
178
180 }
181}
182
185{
186 DPRINTF(SnoopFilter, "%s: packet %s\n", __func__, cpkt->print());
187
188 assert(cpkt->isRequest());
189
190 Addr line_addr = cpkt->getBlockAddr(linesize);
191 if (cpkt->isSecure()) {
192 line_addr |= LineSecure;
193 }
194 auto sf_it = cachedLocations.find(line_addr);
195 bool is_hit = (sf_it != cachedLocations.end());
196
197 panic_if(!is_hit && (cachedLocations.size() >= maxEntryCount),
198 "snoop filter exceeded capacity of %d cache blocks\n",
200
201 // If the snoop filter has no entry, simply return a NULL
202 // portlist, there is no point creating an entry only to remove it
203 // later
204 if (!is_hit)
205 return snoopDown(lookupLatency);
206
207 SnoopItem& sf_item = sf_it->second;
208
209 SnoopMask interested = (sf_item.holder | sf_item.requested);
210
212
213 if (interested.count() == 1)
215 else
217
218 // ReadEx and Writes require both invalidation and exlusivity, while reads
219 // require neither. Writebacks on the other hand require exclusivity but
220 // not the invalidation. Previously Writebacks did not generate upward
221 // snoops so this was never an issue. Now that Writebacks generate snoops
222 // we need a special case for Writebacks. Additionally cache maintenance
223 // operations can generate snoops as they clean and/or invalidate all
224 // caches down to the specified point of reference.
225 assert(cpkt->isWriteback() || cpkt->req->isUncacheable() ||
226 (cpkt->isInvalidate() == cpkt->needsWritable()) ||
227 cpkt->req->isCacheMaintenance());
228 if (cpkt->isInvalidate() && sf_item.requested.none()) {
229 // Early clear of the holder, if no other request is currently going on
230 // @todo: This should possibly be updated even though we do not filter
231 // upward snoops
232 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
233 __func__, sf_item.requested, sf_item.holder);
234 sf_item.holder = 0;
235 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
236 __func__, sf_item.requested, sf_item.holder);
237 eraseIfNullEntry(sf_it);
238 }
239
240 return snoopSelected(maskToPortList(interested), lookupLatency);
241}
242
243void
245 const ResponsePort& rsp_port,
246 const ResponsePort& req_port)
247{
248 DPRINTF(SnoopFilter, "%s: rsp %s req %s packet %s\n",
249 __func__, rsp_port.name(), req_port.name(), cpkt->print());
250
251 assert(cpkt->isResponse());
252 assert(cpkt->cacheResponding());
253
254 // if this snoop response is due to an uncacheable request, or is
255 // being turned into a normal response, there is nothing more to
256 // do
257 if (cpkt->req->isUncacheable() || !req_port.isSnooping()) {
258 return;
259 }
260
261 Addr line_addr = cpkt->getBlockAddr(linesize);
262 if (cpkt->isSecure()) {
263 line_addr |= LineSecure;
264 }
265 SnoopMask rsp_mask = portToMask(rsp_port);
266 SnoopMask req_mask = portToMask(req_port);
267 SnoopItem& sf_item = cachedLocations[line_addr];
268
269 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
270 __func__, sf_item.requested, sf_item.holder);
271
272 // The source should have the line
273 panic_if((sf_item.holder & rsp_mask).none(),
274 "SF value %x.%x does not have the line\n",
275 sf_item.requested, sf_item.holder);
276
277 // The destination should have had a request in
278 panic_if((sf_item.requested & req_mask).none(), "SF value %x.%x missing "\
279 "the original request\n", sf_item.requested, sf_item.holder);
280
281 // If the snoop response has no sharers the line is passed in
282 // Modified state, and we know that there are no other copies, or
283 // they will all be invalidated imminently
284 if (!cpkt->hasSharers()) {
286 "%s: dropping %x because non-shared snoop "
287 "response SF val: %x.%x\n", __func__, rsp_mask,
288 sf_item.requested, sf_item.holder);
289 sf_item.holder = 0;
290 }
291 assert(!cpkt->isWriteback());
292 // @todo Deal with invalidating responses
293 sf_item.holder |= req_mask;
294 sf_item.requested &= ~req_mask;
295 assert((sf_item.requested | sf_item.holder).any());
296 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
297 __func__, sf_item.requested, sf_item.holder);
298}
299
300void
302 const ResponsePort& rsp_port, const RequestPort& req_port)
303{
304 DPRINTF(SnoopFilter, "%s: rsp %s req %s packet %s\n",
305 __func__, rsp_port.name(), req_port.name(), cpkt->print());
306
307 assert(cpkt->isResponse());
308 assert(cpkt->cacheResponding());
309
310 Addr line_addr = cpkt->getBlockAddr(linesize);
311 if (cpkt->isSecure()) {
312 line_addr |= LineSecure;
313 }
314 auto sf_it = cachedLocations.find(line_addr);
315 bool is_hit = sf_it != cachedLocations.end();
316
317 // Nothing to do if it is not a hit
318 if (!is_hit)
319 return;
320
321 // If the snoop response has no sharers the line is passed in
322 // Modified state, and we know that there are no other copies, or
323 // they will all be invalidated imminently
324 if (!cpkt->hasSharers()) {
325 SnoopItem& sf_item = sf_it->second;
326
327 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
328 __func__, sf_item.requested, sf_item.holder);
329 sf_item.holder = 0;
330 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
331 __func__, sf_item.requested, sf_item.holder);
332
333 eraseIfNullEntry(sf_it);
334 }
335}
336
337void
339 cpu_side_port)
340{
341 DPRINTF(SnoopFilter, "%s: src %s packet %s\n",
342 __func__, cpu_side_port.name(), cpkt->print());
343
344 assert(cpkt->isResponse());
345
346 // we only allocate if the packet actually came from a cache, but
347 // start by checking if the port is snooping
348 if (cpkt->req->isUncacheable() || !cpu_side_port.isSnooping())
349 return;
350
351 // next check if we actually allocated an entry
352 Addr line_addr = cpkt->getBlockAddr(linesize);
353 if (cpkt->isSecure()) {
354 line_addr |= LineSecure;
355 }
356 auto sf_it = cachedLocations.find(line_addr);
357 if (sf_it == cachedLocations.end())
358 return;
359
360 SnoopMask response_mask = portToMask(cpu_side_port);
361 SnoopItem& sf_item = sf_it->second;
362
363 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
364 __func__, sf_item.requested, sf_item.holder);
365
366 // Make sure we have seen the actual request, too
367 panic_if((sf_item.requested & response_mask).none(),
368 "SF value %x.%x missing request bit\n",
369 sf_item.requested, sf_item.holder);
370
371 sf_item.requested &= ~response_mask;
372 // Update the residency of the cache line.
373
374 if (cpkt->req->isCacheMaintenance()) {
375 // A cache clean response does not carry any data so it
376 // shouldn't change the holders, unless it is invalidating.
377 if (cpkt->isInvalidate()) {
378 sf_item.holder &= ~response_mask;
379 }
380 eraseIfNullEntry(sf_it);
381 } else {
382 // Any other response implies that a cache above will have the
383 // block.
384 sf_item.holder |= response_mask;
385 assert((sf_item.holder | sf_item.requested).any());
386 }
387 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
388 __func__, sf_item.requested, sf_item.holder);
389}
390
392 : statistics::Group(parent),
393 ADD_STAT(totRequests, statistics::units::Count::get(),
394 "Total number of requests made to the snoop filter."),
395 ADD_STAT(hitSingleRequests, statistics::units::Count::get(),
396 "Number of requests hitting in the snoop filter with a single "
397 "holder of the requested data."),
398 ADD_STAT(hitMultiRequests, statistics::units::Count::get(),
399 "Number of requests hitting in the snoop filter with multiple "
400 "(>1) holders of the requested data."),
401 ADD_STAT(totSnoops, statistics::units::Count::get(),
402 "Total number of snoops made to the snoop filter."),
403 ADD_STAT(hitSingleSnoops, statistics::units::Count::get(),
404 "Number of snoops hitting in the snoop filter with a single "
405 "holder of the requested data."),
406 ADD_STAT(hitMultiSnoops, statistics::units::Count::get(),
407 "Number of snoops hitting in the snoop filter with multiple "
408 "(>1) holders of the requested data.")
409{}
410
411void
416
417} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
bool isSecure() const
Definition packet.hh:836
bool isResponse() const
Definition packet.hh:598
bool needsWritable() const
Definition packet.hh:599
void print(std::ostream &o, int verbosity=0, const std::string &prefix="") const
Definition packet.cc:368
bool needsResponse() const
Definition packet.hh:608
bool fromCache() const
Definition packet.hh:612
Addr getBlockAddr(unsigned int blk_size) const
Definition packet.hh:831
RequestPtr req
A pointer to the original request.
Definition packet.hh:377
bool isWriteback() const
Definition packet.hh:613
bool cacheResponding() const
Definition packet.hh:659
bool isInvalidate() const
Definition packet.hh:609
bool hasSharers() const
Definition packet.hh:686
bool isBlockCached() const
Definition packet.hh:760
bool isEviction() const
Definition packet.hh:610
bool isRequest() const
Definition packet.hh:597
const std::string name() const
Return port name (for DPRINTF).
Definition port.hh:111
A RequestPort is a specialisation of a Port, which implements the default protocol for the three diff...
Definition port.hh:136
A ResponsePort is a specialization of a port.
Definition port.hh:349
bool isSnooping() const
Find out if the peer request port is snooping or not.
Definition port.hh:375
This snoop filter keeps track of which connected port has a particular line of data.
void finishRequest(bool will_retry, Addr addr, bool is_secure)
For an un-successful request, revert the change to the snoop filter.
void eraseIfNullEntry(SnoopFilterCache::iterator &sf_it)
Removes snoop filter items which have no requestors and no holders.
const Cycles lookupLatency
Latency for doing a lookup in the filter.
SnoopMask portToMask(const ResponsePort &port) const
Convert a single port to a corresponding, one-hot bitmask.
void updateSnoopForward(const Packet *cpkt, const ResponsePort &rsp_port, const RequestPort &req_port)
Pass snoop responses that travel downward through the snoop filter and let them update the snoop filt...
void updateResponse(const Packet *cpkt, const ResponsePort &cpu_side_port)
Update the snoop filter with a response from below (outer / other cache, or memory) and update the tr...
const Addr linesize
Cache line size.
std::pair< SnoopList, Cycles > snoopDown(Cycles latency) const
std::bitset< SNOOP_MASK_SIZE > SnoopMask
The underlying type for the bitmask we use for tracking.
std::pair< SnoopList, Cycles > lookupSnoop(const Packet *cpkt)
Handle an incoming snoop from below (the memory-side port).
SnoopList maskToPortList(SnoopMask ports) const
Converts a bitmask of ports into the corresponing list of ports.
struct gem5::SnoopFilter::ReqLookupResult reqLookupResult
std::pair< SnoopList, Cycles > snoopSelected(const SnoopList &_cpu_side_ports, Cycles latency) const
const unsigned maxEntryCount
Max capacity in terms of cache blocks tracked, for sanity checking.
SnoopFilterCache cachedLocations
Simple hash set of cached addresses.
void updateSnoopResponse(const Packet *cpkt, const ResponsePort &rsp_port, const ResponsePort &req_port)
Let the snoop filter see any snoop responses that turn into request responses and indicate cache to c...
@ LineSecure
block holds data from the secure memory space
gem5::SnoopFilter::SnoopFilterStats stats
static const int SNOOP_MASK_SIZE
std::pair< SnoopList, Cycles > lookupRequest(const Packet *cpkt, const ResponsePort &cpu_side_port)
Lookup a request (from a CPU-side port) in the snoop filter and return a list of other CPU-side ports...
virtual void regStats()
Callback to set stat parameters.
Statistics container.
Definition group.hh:93
STL pair class.
Definition stl.hh:58
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition group.hh:75
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
virtual void regStats()
Callback to set stat parameters.
Definition group.cc:68
Bitfield< 3 > addr
Definition types.hh:84
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
Definition of a snoop filter.
SnoopItem retryItem
Variable to temporarily store value of snoopfilter entry in case finishRequest needs to undo changes ...
SnoopFilterCache::iterator it
Iterator used to store the result from lookupRequest.
SnoopFilterStats(statistics::Group *parent)
Per cache line item tracking a bitmask of ResponsePorts who have an outstanding request to this line ...

Generated on Tue Jun 18 2024 16:24:05 for gem5 by doxygen 1.11.0