gem5 v24.0.0.0
Loading...
Searching...
No Matches
RubyPrefetcher.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Inria
3 * Copyright (c) 2020 ARM Limited
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41
43
44#include <cassert>
45
46#include "base/bitfield.hh"
47#include "debug/RubyPrefetcher.hh"
50
51namespace gem5
52{
53
54namespace ruby
55{
56
58 : SimObject(p), m_num_streams(p.num_streams),
59 m_array(p.num_streams), m_train_misses(p.train_misses),
60 m_num_startup_pfs(p.num_startup_pfs),
61 unitFilter(p.unit_filter),
62 negativeFilter(p.unit_filter),
63 nonUnitFilter(p.nonunit_filter),
64 m_prefetch_cross_pages(p.cross_page),
65 pageShift(p.page_shift),
66 rubyPrefetcherStats(this)
67{
68 assert(m_num_streams > 0);
70}
71
74 : statistics::Group(parent, "RubyPrefetcher"),
75 ADD_STAT(numMissObserved, "Number of misses observed"),
76 ADD_STAT(numAllocatedStreams, "Number of streams allocated for "
77 "prefetching"),
78 ADD_STAT(numPrefetchRequested, "Number of prefetch requests made"),
79 ADD_STAT(numHits, "Number of prefetched blocks accessed "
80 "(for the first time)"),
81 ADD_STAT(numPartialHits, "Number of misses observed for a block being "
82 "prefetched"),
83 ADD_STAT(numPagesCrossed, "Number of prefetches across pages"),
84 ADD_STAT(numMissedPrefetchedBlocks, "Number of misses for blocks that "
85 "were prefetched, yet missed")
86{
87}
88
89void
90RubyPrefetcher::observeMiss(Addr address, const RubyRequestType& type)
91{
92 DPRINTF(RubyPrefetcher, "Observed miss for %#x\n", address);
93 Addr line_addr = makeLineAddress(address);
95
96 // check to see if we have already issued a prefetch for this block
97 uint32_t index = 0;
98 PrefetchEntry *pfEntry = getPrefetchEntry(line_addr, index);
99 if (pfEntry != NULL) {
100 if (pfEntry->requestIssued[index]) {
101 if (pfEntry->requestCompleted[index]) {
102 // We prefetched too early and now the prefetch block no
103 // longer exists in the cache
105 return;
106 } else {
107 // The controller has issued the prefetch request,
108 // but the request for the block arrived earlier.
110 observePfMiss(line_addr);
111 return;
112 }
113 } else {
114 // The request is still in the prefetch queue of the controller.
115 // Or was evicted because of other requests.
116 return;
117 }
118 }
119
120 // Check if address is in any of the stride filters
121 if (accessUnitFilter(&unitFilter, line_addr, 1, type)) {
122 DPRINTF(RubyPrefetcher, " *** hit in unit stride buffer\n");
123 return;
124 }
125 if (accessUnitFilter(&negativeFilter, line_addr, -1, type)) {
126 DPRINTF(RubyPrefetcher, " *** hit in unit negative unit buffer\n");
127 return;
128 }
129 if (accessNonunitFilter(line_addr, type)) {
130 DPRINTF(RubyPrefetcher, " *** hit in non-unit stride buffer\n");
131 return;
132 }
133}
134
135void
137{
139 DPRINTF(RubyPrefetcher, "Observed partial hit for %#x\n", address);
140 issueNextPrefetch(address, NULL);
141}
142
143void
145{
147 DPRINTF(RubyPrefetcher, "Observed hit for %#x\n", address);
148 issueNextPrefetch(address, NULL);
149}
150
151void
153{
154 // get our corresponding stream fetcher
155 if (stream == NULL) {
156 uint32_t index = 0;
157 stream = getPrefetchEntry(address, index);
158 }
159
160 // if (for some reason), this stream is unallocated, return.
161 if (stream == NULL) {
162 DPRINTF(RubyPrefetcher, "Unallocated stream, returning\n");
163 return;
164 }
165
166 // extend this prefetching stream by 1 (or more)
167 Addr page_addr = pageAddress(stream->m_address);
168 Addr line_addr = makeNextStrideAddress(stream->m_address,
169 stream->m_stride);
170
171 // possibly stop prefetching at page boundaries
172 if (page_addr != pageAddress(line_addr)) {
174 // Deallocate the stream since we are not prefetching
175 // across page boundries
176 stream->m_is_valid = false;
177 return;
178 }
180 }
181
182 // launch next prefetch
184 stream->m_address = line_addr;
185 stream->m_use_time = m_controller->curCycle();
186 DPRINTF(RubyPrefetcher, "Requesting prefetch for %#x\n", line_addr);
187 m_controller->enqueuePrefetch(line_addr, stream->m_type);
188}
189
190uint32_t
192{
193 uint32_t lru_index = 0;
194 Cycles lru_access = m_array[lru_index].m_use_time;
195
196 for (uint32_t i = 0; i < m_num_streams; i++) {
197 if (!m_array[i].m_is_valid) {
198 return i;
199 }
200 if (m_array[i].m_use_time < lru_access) {
201 lru_access = m_array[i].m_use_time;
202 lru_index = i;
203 }
204 }
205
206 return lru_index;
207}
208
209void
211 uint32_t index, const RubyRequestType& type)
212{
214
215 // initialize the stream prefetcher
216 PrefetchEntry *mystream = &(m_array[index]);
217 mystream->m_address = makeLineAddress(address);
218 mystream->m_stride = stride;
219 mystream->m_use_time = m_controller->curCycle();
220 mystream->m_is_valid = true;
221 mystream->m_type = type;
222
223 // create a number of initial prefetches for this stream
224 Addr page_addr = pageAddress(mystream->m_address);
225 Addr line_addr = makeLineAddress(mystream->m_address);
226
227 // insert a number of prefetches into the prefetch table
228 for (int k = 0; k < m_num_startup_pfs; k++) {
229 line_addr = makeNextStrideAddress(line_addr, stride);
230 // possibly stop prefetching at page boundaries
231 if (page_addr != pageAddress(line_addr)) {
233 // deallocate this stream prefetcher
234 mystream->m_is_valid = false;
235 return;
236 }
238 }
239
240 // launch prefetch
242 DPRINTF(RubyPrefetcher, "Requesting prefetch for %#x\n", line_addr);
243 m_controller->enqueuePrefetch(line_addr, m_array[index].m_type);
244 }
245
246 // update the address to be the last address prefetched
247 mystream->m_address = line_addr;
248}
249
252{
253 // search all streams for a match
254 for (int i = 0; i < m_num_streams; i++) {
255 // search all the outstanding prefetches for this stream
256 if (m_array[i].m_is_valid) {
257 for (int j = 0; j < m_num_startup_pfs; j++) {
258 if (makeNextStrideAddress(m_array[i].m_address,
259 -(m_array[i].m_stride*j)) == address) {
260 return &(m_array[i]);
261 }
262 }
263 }
264 }
265 return NULL;
266}
267
268bool
270 Addr line_addr, int stride, const RubyRequestType& type)
271{
272 for (auto& entry : *filter) {
273 if (entry.addr == line_addr) {
274 entry.addr = makeNextStrideAddress(entry.addr, stride);
275 entry.hits++;
276 if (entry.hits >= m_train_misses) {
277 // Allocate a new prefetch stream
278 initializeStream(line_addr, stride, getLRUindex(), type);
279 }
280 return true;
281 }
282 }
283
284 // Enter this address in the filter
286 makeNextStrideAddress(line_addr, stride)));
287
288 return false;
289}
290
291bool
293 const RubyRequestType& type)
294{
296 Addr page_addr = pageAddress(line_addr);
297
298 for (auto& entry : nonUnitFilter) {
299 if (pageAddress(entry.addr) == page_addr) {
300 // hit in the non-unit filter
301 // compute the actual stride (for this reference)
302 int delta = line_addr - entry.addr;
303
304 if (delta != 0) {
305 // no zero stride prefetches
306 // check that the stride matches (for the last N times)
307 if (delta == entry.stride) {
308 // -> stride hit
309 // increment count (if > 2) allocate stream
310 entry.hits++;
311 if (entry.hits > m_train_misses) {
312 // This stride HAS to be the multiplicative constant of
313 // dataBlockBytes (bc makeNextStrideAddress is
314 // calculated based on this multiplicative constant!)
315 const int stride = entry.stride /
317
318 // clear this filter entry
319 entry.clear();
320
321 initializeStream(line_addr, stride, getLRUindex(),
322 type);
323 }
324 } else {
325 // If delta didn't match reset entry's hit count
326 entry.hits = 0;
327 }
328
329 // update the last address seen & the stride
330 entry.addr = line_addr;
331 entry.stride = delta;
332 return true;
333 } else {
334 return false;
335 }
336 }
337 }
338
339 // not found: enter this address in the table
340 nonUnitFilter.push_back(NonUnitFilterEntry(line_addr));
341
342 return false;
343}
344
345void
346RubyPrefetcher::print(std::ostream& out) const
347{
348 out << name() << " Prefetcher State\n";
349 // print out unit filter
350 out << "unit table:\n";
351 for (const auto& entry : unitFilter) {
352 out << entry.addr << std::endl;
353 }
354
355 out << "negative table:\n";
356 for (const auto& entry : negativeFilter) {
357 out << entry.addr << std::endl;
358 }
359
360 // print out non-unit stride filter
361 out << "non-unit table:\n";
362 for (const auto& entry : nonUnitFilter) {
363 out << entry.addr << " "
364 << entry.stride << " "
365 << entry.hits << std::endl;
366 }
367
368 // print out allocated stream buffers
369 out << "streams:\n";
370 for (int i = 0; i < m_num_streams; i++) {
371 out << m_array[i].m_address << " "
372 << m_array[i].m_stride << " "
373 << m_array[i].m_is_valid << " "
374 << m_array[i].m_use_time << std::endl;
375 }
376}
377
378Addr
383
384} // namespace ruby
385} // namespace gem5
#define MAX_PF_INFLIGHT
#define DPRINTF(x,...)
Definition trace.hh:210
Circular queue.
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Cycles is a wrapper class for representing cycle counts, i.e.
Definition types.hh:79
virtual std::string name() const
Definition named.hh:47
Abstract superclass for simulation objects.
virtual void enqueuePrefetch(const Addr &, const RubyRequestType &)
Function for enqueuing a prefetch request.
RubyRequestType m_type
L1D prefetches loads and stores.
int m_stride
stride distance to get next address from
std::bitset< MAX_PF_INFLIGHT > requestIssued
Bitset for tracking prefetches for which addresses have been issued, which ones have completed.
bool m_is_valid
valid bit for each stream
std::bitset< MAX_PF_INFLIGHT > requestCompleted
Cycles m_use_time
the last time that any prefetched request was used
Addr m_address
The base address for the stream prefetch.
CircularQueue< UnitFilterEntry > negativeFilter
A negative unit stride filter array: helps reduce BW requirement of prefetching.
void initializeStream(Addr address, int stride, uint32_t index, const RubyRequestType &type)
allocate a new stream buffer at a specific index
uint32_t m_num_streams
number of prefetch streams available
gem5::ruby::RubyPrefetcher::RubyPrefetcherStats rubyPrefetcherStats
bool accessNonunitFilter(Addr line_addr, const RubyRequestType &type)
Access a non-unit stride filter to determine if there is a hit, and update it otherwise.
RubyPrefetcher(const Params &p)
PrefetchEntry * getPrefetchEntry(Addr address, uint32_t &index)
get pointer to the matching stream entry, returns NULL if not found index holds the multiple of the s...
CircularQueue< UnitFilterEntry > unitFilter
A unit stride filter array: helps reduce BW requirement of prefetching.
void observeMiss(Addr address, const RubyRequestType &type)
Observe a memory miss from the cache.
AbstractController * m_controller
void observePfHit(Addr address)
Implement the prefetch hit(miss) callback interface.
uint32_t m_num_startup_pfs
number of initial prefetches to startup a stream
void print(std::ostream &out) const
Print out some statistics.
std::vector< PrefetchEntry > m_array
an array of the active prefetch streams
CircularQueue< NonUnitFilterEntry > nonUnitFilter
A non-unit stride filter array: helps reduce BW requirement of prefetching.
uint32_t getLRUindex(void)
Returns an unused stream buffer (or if all are used, returns the least recently used (accessed) strea...
RubyPrefetcherParams Params
void issueNextPrefetch(Addr address, PrefetchEntry *stream)
void observePfMiss(Addr address)
bool accessUnitFilter(CircularQueue< UnitFilterEntry > *const filter, Addr line_addr, int stride, const RubyRequestType &type)
Access a unit stride filter to determine if there is a hit, and update it otherwise.
uint32_t m_train_misses
number of misses I must see before allocating a stream
bool m_prefetch_cross_pages
Used for allowing prefetches across pages.
Addr pageAddress(Addr addr) const
determine the page aligned address
static uint32_t getBlockSizeBytes()
Definition RubySystem.hh:72
Statistics container.
Definition group.hh:93
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition group.hh:75
void push_back(typename std::vector< T >::value_type val)
Pushes an element at the end of the queue.
constexpr T mbits(T val, unsigned first, unsigned last)
Mask off the given bits in place like bits() but without shifting.
Definition bitfield.hh:106
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 21, 20 > stride
Bitfield< 30, 0 > index
Bitfield< 0 > p
Bitfield< 23 > k
Bitfield< 3 > addr
Definition types.hh:84
Addr makeNextStrideAddress(Addr addr, int stride)
Definition Address.cc:73
Addr makeLineAddress(Addr addr)
Definition Address.cc:60
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
statistics::Scalar numPartialHits
Count of partial successful prefetches.
statistics::Scalar numPagesCrossed
Count of pages crossed.
statistics::Scalar numMissObserved
Count of accesses to the prefetcher.
statistics::Scalar numHits
Count of successful prefetches.
statistics::Scalar numAllocatedStreams
Count of prefetch streams allocated.
statistics::Scalar numPrefetchRequested
Count of prefetch requests made.
statistics::Scalar numMissedPrefetchedBlocks
Count of misses incurred for blocks that were prefetched.

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