gem5  v21.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 
52  : SimObject(p), m_num_streams(p.num_streams),
53  m_array(p.num_streams), m_train_misses(p.train_misses),
54  m_num_startup_pfs(p.num_startup_pfs),
55  unitFilter(p.unit_filter),
56  negativeFilter(p.unit_filter),
57  nonUnitFilter(p.nonunit_filter),
58  m_prefetch_cross_pages(p.cross_page),
59  m_page_shift(p.sys->getPageShift()),
60  rubyPrefetcherStats(this)
61 {
62  assert(m_num_streams > 0);
64 }
65 
68  : Stats::Group(parent, "RubyPrefetcher"),
69  ADD_STAT(numMissObserved, "Number of misses observed"),
70  ADD_STAT(numAllocatedStreams, "Number of streams allocated for "
71  "prefetching"),
72  ADD_STAT(numPrefetchRequested, "Number of prefetch requests made"),
73  ADD_STAT(numHits, "Number of prefetched blocks accessed "
74  "(for the first time)"),
75  ADD_STAT(numPartialHits, "Number of misses observed for a block being "
76  "prefetched"),
77  ADD_STAT(numPagesCrossed, "Number of prefetches across pages"),
78  ADD_STAT(numMissedPrefetchedBlocks, "Number of misses for blocks that "
79  "were prefetched, yet missed")
80 {
81 }
82 
83 void
84 RubyPrefetcher::observeMiss(Addr address, const RubyRequestType& type)
85 {
86  DPRINTF(RubyPrefetcher, "Observed miss for %#x\n", address);
87  Addr line_addr = makeLineAddress(address);
89 
90  // check to see if we have already issued a prefetch for this block
91  uint32_t index = 0;
92  PrefetchEntry *pfEntry = getPrefetchEntry(line_addr, index);
93  if (pfEntry != NULL) {
94  if (pfEntry->requestIssued[index]) {
95  if (pfEntry->requestCompleted[index]) {
96  // We prefetched too early and now the prefetch block no
97  // longer exists in the cache
99  return;
100  } else {
101  // The controller has issued the prefetch request,
102  // but the request for the block arrived earlier.
104  observePfMiss(line_addr);
105  return;
106  }
107  } else {
108  // The request is still in the prefetch queue of the controller.
109  // Or was evicted because of other requests.
110  return;
111  }
112  }
113 
114  // Check if address is in any of the stride filters
115  if (accessUnitFilter(&unitFilter, line_addr, 1, type)) {
116  DPRINTF(RubyPrefetcher, " *** hit in unit stride buffer\n");
117  return;
118  }
119  if (accessUnitFilter(&negativeFilter, line_addr, -1, type)) {
120  DPRINTF(RubyPrefetcher, " *** hit in unit negative unit buffer\n");
121  return;
122  }
123  if (accessNonunitFilter(line_addr, type)) {
124  DPRINTF(RubyPrefetcher, " *** hit in non-unit stride buffer\n");
125  return;
126  }
127 }
128 
129 void
131 {
133  DPRINTF(RubyPrefetcher, "Observed partial hit for %#x\n", address);
134  issueNextPrefetch(address, NULL);
135 }
136 
137 void
139 {
141  DPRINTF(RubyPrefetcher, "Observed hit for %#x\n", address);
142  issueNextPrefetch(address, NULL);
143 }
144 
145 void
147 {
148  // get our corresponding stream fetcher
149  if (stream == NULL) {
150  uint32_t index = 0;
151  stream = getPrefetchEntry(address, index);
152  }
153 
154  // if (for some reason), this stream is unallocated, return.
155  if (stream == NULL) {
156  DPRINTF(RubyPrefetcher, "Unallocated stream, returning\n");
157  return;
158  }
159 
160  // extend this prefetching stream by 1 (or more)
161  Addr page_addr = pageAddress(stream->m_address);
162  Addr line_addr = makeNextStrideAddress(stream->m_address,
163  stream->m_stride);
164 
165  // possibly stop prefetching at page boundaries
166  if (page_addr != pageAddress(line_addr)) {
167  if (!m_prefetch_cross_pages) {
168  // Deallocate the stream since we are not prefetching
169  // across page boundries
170  stream->m_is_valid = false;
171  return;
172  }
174  }
175 
176  // launch next prefetch
178  stream->m_address = line_addr;
179  stream->m_use_time = m_controller->curCycle();
180  DPRINTF(RubyPrefetcher, "Requesting prefetch for %#x\n", line_addr);
181  m_controller->enqueuePrefetch(line_addr, stream->m_type);
182 }
183 
184 uint32_t
186 {
187  uint32_t lru_index = 0;
188  Cycles lru_access = m_array[lru_index].m_use_time;
189 
190  for (uint32_t i = 0; i < m_num_streams; i++) {
191  if (!m_array[i].m_is_valid) {
192  return i;
193  }
194  if (m_array[i].m_use_time < lru_access) {
195  lru_access = m_array[i].m_use_time;
196  lru_index = i;
197  }
198  }
199 
200  return lru_index;
201 }
202 
203 void
205  uint32_t index, const RubyRequestType& type)
206 {
208 
209  // initialize the stream prefetcher
210  PrefetchEntry *mystream = &(m_array[index]);
211  mystream->m_address = makeLineAddress(address);
212  mystream->m_stride = stride;
213  mystream->m_use_time = m_controller->curCycle();
214  mystream->m_is_valid = true;
215  mystream->m_type = type;
216 
217  // create a number of initial prefetches for this stream
218  Addr page_addr = pageAddress(mystream->m_address);
219  Addr line_addr = makeLineAddress(mystream->m_address);
220 
221  // insert a number of prefetches into the prefetch table
222  for (int k = 0; k < m_num_startup_pfs; k++) {
223  line_addr = makeNextStrideAddress(line_addr, stride);
224  // possibly stop prefetching at page boundaries
225  if (page_addr != pageAddress(line_addr)) {
226  if (!m_prefetch_cross_pages) {
227  // deallocate this stream prefetcher
228  mystream->m_is_valid = false;
229  return;
230  }
232  }
233 
234  // launch prefetch
236  DPRINTF(RubyPrefetcher, "Requesting prefetch for %#x\n", line_addr);
237  m_controller->enqueuePrefetch(line_addr, m_array[index].m_type);
238  }
239 
240  // update the address to be the last address prefetched
241  mystream->m_address = line_addr;
242 }
243 
246 {
247  // search all streams for a match
248  for (int i = 0; i < m_num_streams; i++) {
249  // search all the outstanding prefetches for this stream
250  if (m_array[i].m_is_valid) {
251  for (int j = 0; j < m_num_startup_pfs; j++) {
252  if (makeNextStrideAddress(m_array[i].m_address,
253  -(m_array[i].m_stride*j)) == address) {
254  return &(m_array[i]);
255  }
256  }
257  }
258  }
259  return NULL;
260 }
261 
262 bool
264  Addr line_addr, int stride, const RubyRequestType& type)
265 {
266  for (auto& entry : *filter) {
267  if (entry.addr == line_addr) {
268  entry.addr = makeNextStrideAddress(entry.addr, stride);
269  entry.hits++;
270  if (entry.hits >= m_train_misses) {
271  // Allocate a new prefetch stream
272  initializeStream(line_addr, stride, getLRUindex(), type);
273  }
274  return true;
275  }
276  }
277 
278  // Enter this address in the filter
279  filter->push_back(UnitFilterEntry(
280  makeNextStrideAddress(line_addr, stride)));
281 
282  return false;
283 }
284 
285 bool
287  const RubyRequestType& type)
288 {
290  Addr page_addr = pageAddress(line_addr);
291 
292  for (auto& entry : nonUnitFilter) {
293  if (pageAddress(entry.addr) == page_addr) {
294  // hit in the non-unit filter
295  // compute the actual stride (for this reference)
296  int delta = line_addr - entry.addr;
297 
298  if (delta != 0) {
299  // no zero stride prefetches
300  // check that the stride matches (for the last N times)
301  if (delta == entry.stride) {
302  // -> stride hit
303  // increment count (if > 2) allocate stream
304  entry.hits++;
305  if (entry.hits > m_train_misses) {
306  // This stride HAS to be the multiplicative constant of
307  // dataBlockBytes (bc makeNextStrideAddress is
308  // calculated based on this multiplicative constant!)
309  const int stride = entry.stride /
311 
312  // clear this filter entry
313  entry.clear();
314 
315  initializeStream(line_addr, stride, getLRUindex(),
316  type);
317  }
318  } else {
319  // If delta didn't match reset entry's hit count
320  entry.hits = 0;
321  }
322 
323  // update the last address seen & the stride
324  entry.addr = line_addr;
325  entry.stride = delta;
326  return true;
327  } else {
328  return false;
329  }
330  }
331  }
332 
333  // not found: enter this address in the table
334  nonUnitFilter.push_back(NonUnitFilterEntry(line_addr));
335 
336  return false;
337 }
338 
339 void
340 RubyPrefetcher::print(std::ostream& out) const
341 {
342  out << name() << " Prefetcher State\n";
343  // print out unit filter
344  out << "unit table:\n";
345  for (const auto& entry : unitFilter) {
346  out << entry.addr << std::endl;
347  }
348 
349  out << "negative table:\n";
350  for (const auto& entry : negativeFilter) {
351  out << entry.addr << std::endl;
352  }
353 
354  // print out non-unit stride filter
355  out << "non-unit table:\n";
356  for (const auto& entry : nonUnitFilter) {
357  out << entry.addr << " "
358  << entry.stride << " "
359  << entry.hits << std::endl;
360  }
361 
362  // print out allocated stream buffers
363  out << "streams:\n";
364  for (int i = 0; i < m_num_streams; i++) {
365  out << m_array[i].m_address << " "
366  << m_array[i].m_stride << " "
367  << m_array[i].m_is_valid << " "
368  << m_array[i].m_use_time << std::endl;
369  }
370 }
371 
372 Addr
374 {
375  return mbits<Addr>(addr, 63, m_page_shift);
376 }
PrefetchEntry::m_type
RubyRequestType m_type
L1D prefetches loads and stores.
Definition: RubyPrefetcher.hh:87
RubyPrefetcher::pageAddress
Addr pageAddress(Addr addr) const
determine the page aligned address
Definition: RubyPrefetcher.cc:373
RubyPrefetcher::print
void print(std::ostream &out) const
Print out some statistics.
Definition: RubyPrefetcher.cc:340
RubyPrefetcher::m_num_startup_pfs
uint32_t m_num_startup_pfs
number of initial prefetches to startup a stream
Definition: RubyPrefetcher.hh:210
RubySystem::getBlockSizeBytes
static uint32_t getBlockSizeBytes()
Definition: RubySystem.hh:61
MipsISA::index
Bitfield< 30, 0 > index
Definition: pra_constants.hh:44
RubyPrefetcher::NonUnitFilterEntry
Definition: RubyPrefetcher.hh:140
RubyPrefetcher::unitFilter
CircularQueue< UnitFilterEntry > unitFilter
A unit stride filter array: helps reduce BW requirement of prefetching.
Definition: RubyPrefetcher.hh:216
makeLineAddress
Addr makeLineAddress(Addr addr)
Definition: Address.cc:54
PrefetchEntry::m_use_time
Cycles m_use_time
the last time that any prefetched request was used
Definition: RubyPrefetcher.hh:81
ArmISA::i
Bitfield< 7 > i
Definition: miscregs_types.hh:63
RubyPrefetcher::issueNextPrefetch
void issueNextPrefetch(Addr address, PrefetchEntry *stream)
Definition: RubyPrefetcher.cc:146
PrefetchEntry::m_stride
int m_stride
stride distance to get next address from
Definition: RubyPrefetcher.hh:78
RubyPrefetcher::RubyPrefetcherStats::numPartialHits
Stats::Scalar numPartialHits
Count of partial successful prefetches.
Definition: RubyPrefetcher.hh:250
RubyPrefetcher::UnitFilterEntry
Definition: RubyPrefetcher.hh:127
RubyPrefetcher::m_num_streams
uint32_t m_num_streams
number of prefetch streams available
Definition: RubyPrefetcher.hh:203
CircularQueue
Circular queue.
Definition: circular_queue.hh:66
PrefetchEntry::requestCompleted
std::bitset< MAX_PF_INFLIGHT > requestCompleted
Definition: RubyPrefetcher.hh:92
RubyPrefetcher::observeMiss
void observeMiss(Addr address, const RubyRequestType &type)
Observe a memory miss from the cache.
Definition: RubyPrefetcher.cc:84
RubyPrefetcher::RubyPrefetcherStats::numPrefetchRequested
Stats::Scalar numPrefetchRequested
Count of prefetch requests made.
Definition: RubyPrefetcher.hh:246
RubyPrefetcher
Definition: RubyPrefetcher.hh:95
PrefetchEntry::m_is_valid
bool m_is_valid
valid bit for each stream
Definition: RubyPrefetcher.hh:84
PrefetchEntry::requestIssued
std::bitset< MAX_PF_INFLIGHT > requestIssued
Bitset for tracking prefetches for which addresses have been issued, which ones have completed.
Definition: RubyPrefetcher.hh:91
RubyPrefetcher::RubyPrefetcherStats::RubyPrefetcherStats
RubyPrefetcherStats(Stats::Group *parent)
Definition: RubyPrefetcher.cc:67
makeNextStrideAddress
Addr makeNextStrideAddress(Addr addr, int stride)
Definition: Address.cc:67
RubyPrefetcher::observePfHit
void observePfHit(Addr address)
Implement the prefetch hit(miss) callback interface.
Definition: RubyPrefetcher.cc:138
ArmISA::j
Bitfield< 24 > j
Definition: miscregs_types.hh:54
RubyPrefetcher.hh
RubyPrefetcher::RubyPrefetcherStats::numPagesCrossed
Stats::Scalar numPagesCrossed
Count of pages crossed.
Definition: RubyPrefetcher.hh:252
MipsISA::k
Bitfield< 23 > k
Definition: dt_constants.hh:78
bitfield.hh
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:237
ADD_STAT
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition: group.hh:71
Clocked::curCycle
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Definition: clocked_object.hh:192
RubyPrefetcher::m_controller
AbstractController * m_controller
Definition: RubyPrefetcher.hh:233
RubySystem.hh
MAX_PF_INFLIGHT
#define MAX_PF_INFLIGHT
Definition: RubyPrefetcher.hh:60
RubyPrefetcher::RubyPrefetcherStats::numHits
Stats::Scalar numHits
Count of successful prefetches.
Definition: RubyPrefetcher.hh:248
RubyPrefetcher::getLRUindex
uint32_t getLRUindex(void)
Returns an unused stream buffer (or if all are used, returns the least recently used (accessed) strea...
Definition: RubyPrefetcher.cc:185
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:148
RubyPrefetcher::RubyPrefetcherStats::numAllocatedStreams
Stats::Scalar numAllocatedStreams
Count of prefetch streams allocated.
Definition: RubyPrefetcher.hh:244
RubyPrefetcher::RubyPrefetcherStats::numMissedPrefetchedBlocks
Stats::Scalar numMissedPrefetchedBlocks
Count of misses incurred for blocks that were prefetched.
Definition: RubyPrefetcher.hh:254
RubySlicc_ComponentMapping.hh
PrefetchEntry
Definition: RubyPrefetcher.hh:62
X86ISA::addr
Bitfield< 3 > addr
Definition: types.hh:80
SimObject::name
virtual const std::string name() const
Definition: sim_object.hh:182
RubyPrefetcher::negativeFilter
CircularQueue< UnitFilterEntry > negativeFilter
A negative unit stride filter array: helps reduce BW requirement of prefetching.
Definition: RubyPrefetcher.hh:222
RubyPrefetcher::observePfMiss
void observePfMiss(Addr address)
Definition: RubyPrefetcher.cc:130
RubyPrefetcher::initializeStream
void initializeStream(Addr address, int stride, uint32_t index, const RubyRequestType &type)
allocate a new stream buffer at a specific index
Definition: RubyPrefetcher.cc:204
RubyPrefetcher::m_page_shift
const Addr m_page_shift
Definition: RubyPrefetcher.hh:235
Stats::Group
Statistics container.
Definition: group.hh:87
RubyPrefetcher::m_array
std::vector< PrefetchEntry > m_array
an array of the active prefetch streams
Definition: RubyPrefetcher.hh:205
RubyPrefetcher::rubyPrefetcherStats
RubyPrefetcher::RubyPrefetcherStats rubyPrefetcherStats
RubyPrefetcher::accessNonunitFilter
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.
Definition: RubyPrefetcher.cc:286
PrefetchEntry::m_address
Addr m_address
The base address for the stream prefetch.
Definition: RubyPrefetcher.hh:75
ArmISA::stride
Bitfield< 21, 20 > stride
Definition: miscregs_types.hh:441
RubyPrefetcher::Params
RubyPrefetcherParams Params
Definition: RubyPrefetcher.hh:98
Cycles
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
RubyPrefetcher::getPrefetchEntry
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...
Definition: RubyPrefetcher.cc:245
RubyPrefetcher::m_train_misses
uint32_t m_train_misses
number of misses I must see before allocating a stream
Definition: RubyPrefetcher.hh:208
X86ISA::type
type
Definition: misc.hh:727
RubyPrefetcher::RubyPrefetcherStats::numMissObserved
Stats::Scalar numMissObserved
Count of accesses to the prefetcher.
Definition: RubyPrefetcher.hh:242
Stats
Definition: statistics.cc:53
RubyPrefetcher::accessUnitFilter
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.
Definition: RubyPrefetcher.cc:263
AbstractController::enqueuePrefetch
virtual void enqueuePrefetch(const Addr &, const RubyRequestType &)
Function for enqueuing a prefetch request.
Definition: AbstractController.hh:137
RubyPrefetcher::m_prefetch_cross_pages
bool m_prefetch_cross_pages
Used for allowing prefetches across pages.
Definition: RubyPrefetcher.hh:231
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
RubyPrefetcher::RubyPrefetcher
RubyPrefetcher(const Params &p)
Definition: RubyPrefetcher.cc:51
RubyPrefetcher::nonUnitFilter
CircularQueue< NonUnitFilterEntry > nonUnitFilter
A non-unit stride filter array: helps reduce BW requirement of prefetching.
Definition: RubyPrefetcher.hh:228
SimObject
Abstract superclass for simulation objects.
Definition: sim_object.hh:141

Generated on Tue Mar 23 2021 19:41:28 for gem5 by doxygen 1.8.17