gem5  v19.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Prefetcher.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
30 
31 #include "base/bitfield.hh"
32 #include "debug/RubyPrefetcher.hh"
35 
37 PrefetcherParams::create()
38 {
39  return new Prefetcher(this);
40 }
41 
43  : SimObject(p), m_num_streams(p->num_streams),
44  m_array(p->num_streams), m_train_misses(p->train_misses),
45  m_num_startup_pfs(p->num_startup_pfs), m_num_unit_filters(p->unit_filter),
46  m_num_nonunit_filters(p->nonunit_filter),
47  m_unit_filter(p->unit_filter, 0),
48  m_negative_filter(p->unit_filter, 0),
49  m_nonunit_filter(p->nonunit_filter, 0),
50  m_prefetch_cross_pages(p->cross_page),
51  m_page_shift(p->sys->getPageShift())
52 {
53  assert(m_num_streams > 0);
55 
56  // create +1 stride filter
58  m_unit_filter_hit = new uint32_t[m_num_unit_filters];
59  for (uint32_t i =0; i < m_num_unit_filters; i++) {
60  m_unit_filter_hit[i] = 0;
61  }
62 
63  // create -1 stride filter
66  for (int i =0; i < m_num_unit_filters; i++) {
68  }
69 
70  // create nonunit stride filter
71  m_nonunit_index = 0;
73  m_nonunit_hit = new uint32_t[m_num_nonunit_filters];
74  for (int i =0; i < m_num_nonunit_filters; i++) {
75  m_nonunit_stride[i] = 0;
76  m_nonunit_hit[i] = 0;
77  }
78 }
79 
81 {
82  delete m_unit_filter_hit;
83  delete m_negative_filter_hit;
84  delete m_nonunit_stride;
85  delete m_nonunit_hit;
86 }
87 
88 void
90 {
92 
94  .name(name() + ".miss_observed")
95  .desc("number of misses observed")
96  ;
97 
99  .name(name() + ".allocated_streams")
100  .desc("number of streams allocated for prefetching")
101  ;
102 
104  .name(name() + ".prefetches_requested")
105  .desc("number of prefetch requests made")
106  ;
107 
109  .name(name() + ".prefetches_accepted")
110  .desc("number of prefetch requests accepted")
111  ;
112 
114  .name(name() + ".dropped_prefetches")
115  .desc("number of prefetch requests dropped")
116  ;
117 
118  numHits
119  .name(name() + ".hits")
120  .desc("number of prefetched blocks accessed")
121  ;
122 
124  .name(name() + ".partial_hits")
125  .desc("number of misses observed for a block being prefetched")
126  ;
127 
129  .name(name() + ".pages_crossed")
130  .desc("number of prefetches across pages")
131  ;
132 
134  .name(name() + ".misses_on_prefetched_blocks")
135  .desc("number of misses for blocks that were prefetched, yet missed")
136  ;
137 }
138 
139 void
140 Prefetcher::observeMiss(Addr address, const RubyRequestType& type)
141 {
142  DPRINTF(RubyPrefetcher, "Observed miss for %#x\n", address);
143  Addr line_addr = makeLineAddress(address);
144  numMissObserved++;
145 
146  // check to see if we have already issued a prefetch for this block
147  uint32_t index = 0;
148  PrefetchEntry *pfEntry = getPrefetchEntry(line_addr, index);
149  if (pfEntry != NULL) {
150  if (pfEntry->requestIssued[index]) {
151  if (pfEntry->requestCompleted[index]) {
152  // We prefetched too early and now the prefetch block no
153  // longer exists in the cache
155  return;
156  } else {
157  // The controller has issued the prefetch request,
158  // but the request for the block arrived earlier.
159  numPartialHits++;
160  observePfHit(line_addr);
161  return;
162  }
163  } else {
164  // The request is still in the prefetch queue of the controller.
165  // Or was evicted because of other requests.
166  return;
167  }
168  }
169 
170  // check to see if this address is in the unit stride filter
171  bool alloc = false;
173  m_unit_filter_index, line_addr, 1, alloc);
174  if (alloc) {
175  // allocate a new prefetch stream
176  initializeStream(line_addr, 1, getLRUindex(), type);
177  }
178  if (hit) {
179  DPRINTF(RubyPrefetcher, " *** hit in unit stride buffer\n");
180  return;
181  }
182 
184  m_negative_filter_index, line_addr, -1, alloc);
185  if (alloc) {
186  // allocate a new prefetch stream
187  initializeStream(line_addr, -1, getLRUindex(), type);
188  }
189  if (hit) {
190  DPRINTF(RubyPrefetcher, " *** hit in unit negative unit buffer\n");
191  return;
192  }
193 
194  // check to see if this address is in the non-unit stride filter
195  int stride = 0; // NULL value
196  hit = accessNonunitFilter(address, &stride, alloc);
197  if (alloc) {
198  assert(stride != 0); // ensure non-zero stride prefetches
199  initializeStream(line_addr, stride, getLRUindex(), type);
200  }
201  if (hit) {
202  DPRINTF(RubyPrefetcher, " *** hit in non-unit stride buffer\n");
203  return;
204  }
205 }
206 
207 void
209 {
210  numPartialHits++;
211  DPRINTF(RubyPrefetcher, "Observed partial hit for %#x\n", address);
212  issueNextPrefetch(address, NULL);
213 }
214 
215 void
217 {
218  numHits++;
219  DPRINTF(RubyPrefetcher, "Observed hit for %#x\n", address);
220  issueNextPrefetch(address, NULL);
221 }
222 
223 void
225 {
226  // get our corresponding stream fetcher
227  if (stream == NULL) {
228  uint32_t index = 0;
229  stream = getPrefetchEntry(address, index);
230  }
231 
232  // if (for some reason), this stream is unallocated, return.
233  if (stream == NULL) {
234  DPRINTF(RubyPrefetcher, "Unallocated stream, returning\n");
235  return;
236  }
237 
238  // extend this prefetching stream by 1 (or more)
239  Addr page_addr = pageAddress(stream->m_address);
240  Addr line_addr = makeNextStrideAddress(stream->m_address,
241  stream->m_stride);
242 
243  // possibly stop prefetching at page boundaries
244  if (page_addr != pageAddress(line_addr)) {
245  numPagesCrossed++;
246  if (!m_prefetch_cross_pages) {
247  // Deallocate the stream since we are not prefetching
248  // across page boundries
249  stream->m_is_valid = false;
250  return;
251  }
252  }
253 
254  // launch next prefetch
255  stream->m_address = line_addr;
256  stream->m_use_time = m_controller->curCycle();
257  DPRINTF(RubyPrefetcher, "Requesting prefetch for %#x\n", line_addr);
258  m_controller->enqueuePrefetch(line_addr, stream->m_type);
259 }
260 
261 uint32_t
263 {
264  uint32_t lru_index = 0;
265  Cycles lru_access = m_array[lru_index].m_use_time;
266 
267  for (uint32_t i = 0; i < m_num_streams; i++) {
268  if (!m_array[i].m_is_valid) {
269  return i;
270  }
271  if (m_array[i].m_use_time < lru_access) {
272  lru_access = m_array[i].m_use_time;
273  lru_index = i;
274  }
275  }
276 
277  return lru_index;
278 }
279 
280 void
282 {
283  m_nonunit_filter[index] = 0;
284  m_nonunit_stride[index] = 0;
285  m_nonunit_hit[index] = 0;
286 }
287 
288 void
290  uint32_t index, const RubyRequestType& type)
291 {
293 
294  // initialize the stream prefetcher
295  PrefetchEntry *mystream = &(m_array[index]);
296  mystream->m_address = makeLineAddress(address);
297  mystream->m_stride = stride;
298  mystream->m_use_time = m_controller->curCycle();
299  mystream->m_is_valid = true;
300  mystream->m_type = type;
301 
302  // create a number of initial prefetches for this stream
303  Addr page_addr = pageAddress(mystream->m_address);
304  Addr line_addr = makeLineAddress(mystream->m_address);
305 
306  // insert a number of prefetches into the prefetch table
307  for (int k = 0; k < m_num_startup_pfs; k++) {
308  line_addr = makeNextStrideAddress(line_addr, stride);
309  // possibly stop prefetching at page boundaries
310  if (page_addr != pageAddress(line_addr)) {
311  numPagesCrossed++;
312  if (!m_prefetch_cross_pages) {
313  // deallocate this stream prefetcher
314  mystream->m_is_valid = false;
315  return;
316  }
317  }
318 
319  // launch prefetch
321  DPRINTF(RubyPrefetcher, "Requesting prefetch for %#x\n", line_addr);
322  m_controller->enqueuePrefetch(line_addr, m_array[index].m_type);
323  }
324 
325  // update the address to be the last address prefetched
326  mystream->m_address = line_addr;
327 }
328 
331 {
332  // search all streams for a match
333  for (int i = 0; i < m_num_streams; i++) {
334  // search all the outstanding prefetches for this stream
335  if (m_array[i].m_is_valid) {
336  for (int j = 0; j < m_num_startup_pfs; j++) {
337  if (makeNextStrideAddress(m_array[i].m_address,
338  -(m_array[i].m_stride*j)) == address) {
339  return &(m_array[i]);
340  }
341  }
342  }
343  }
344  return NULL;
345 }
346 
347 bool
349  uint32_t *filter_hit, uint32_t &index, Addr address,
350  int stride, bool &alloc)
351 {
352  //reset the alloc flag
353  alloc = false;
354 
355  Addr line_addr = makeLineAddress(address);
356  for (int i = 0; i < m_num_unit_filters; i++) {
357  if (filter_table[i] == line_addr) {
358  filter_table[i] = makeNextStrideAddress(filter_table[i], stride);
359  filter_hit[i]++;
360  if (filter_hit[i] >= m_train_misses) {
361  alloc = true;
362  }
363  return true;
364  }
365  }
366 
367  // enter this address in the table
368  int local_index = index;
369  filter_table[local_index] = makeNextStrideAddress(line_addr, stride);
370  filter_hit[local_index] = 0;
371  local_index = local_index + 1;
372  if (local_index >= m_num_unit_filters) {
373  local_index = 0;
374  }
375 
376  index = local_index;
377  return false;
378 }
379 
380 bool
382  bool &alloc)
383 {
384  //reset the alloc flag
385  alloc = false;
386 
388  Addr page_addr = pageAddress(address);
389  Addr line_addr = makeLineAddress(address);
390 
391  for (uint32_t i = 0; i < m_num_nonunit_filters; i++) {
392  if (pageAddress(m_nonunit_filter[i]) == page_addr) {
393  // hit in the non-unit filter
394  // compute the actual stride (for this reference)
395  int delta = line_addr - m_nonunit_filter[i];
396 
397  if (delta != 0) {
398  // no zero stride prefetches
399  // check that the stride matches (for the last N times)
400  if (delta == m_nonunit_stride[i]) {
401  // -> stride hit
402  // increment count (if > 2) allocate stream
403  m_nonunit_hit[i]++;
404  if (m_nonunit_hit[i] > m_train_misses) {
405  // This stride HAS to be the multiplicative constant of
406  // dataBlockBytes (bc makeNextStrideAddress is
407  // calculated based on this multiplicative constant!)
408  *stride = m_nonunit_stride[i] /
410 
411  // clear this filter entry
413  alloc = true;
414  }
415  } else {
416  // delta didn't match ... reset m_nonunit_hit count for
417  // this entry
418  m_nonunit_hit[i] = 0;
419  }
420 
421  // update the last address seen & the stride
422  m_nonunit_stride[i] = delta;
423  m_nonunit_filter[i] = line_addr;
424  return true;
425  } else {
426  return false;
427  }
428  }
429  }
430 
431  // not found: enter this address in the table
432  m_nonunit_filter[m_nonunit_index] = line_addr;
435 
437  if (m_nonunit_index >= m_num_nonunit_filters) {
438  m_nonunit_index = 0;
439  }
440  return false;
441 }
442 
443 void
444 Prefetcher::print(std::ostream& out) const
445 {
446  out << name() << " Prefetcher State\n";
447  // print out unit filter
448  out << "unit table:\n";
449  for (int i = 0; i < m_num_unit_filters; i++) {
450  out << m_unit_filter[i] << std::endl;
451  }
452 
453  out << "negative table:\n";
454  for (int i = 0; i < m_num_unit_filters; i++) {
455  out << m_negative_filter[i] << std::endl;
456  }
457 
458  // print out non-unit stride filter
459  out << "non-unit table:\n";
460  for (int i = 0; i < m_num_nonunit_filters; i++) {
461  out << m_nonunit_filter[i] << " "
462  << m_nonunit_stride[i] << " "
463  << m_nonunit_hit[i] << std::endl;
464  }
465 
466  // print out allocated stream buffers
467  out << "streams:\n";
468  for (int i = 0; i < m_num_streams; i++) {
469  out << m_array[i].m_address << " "
470  << m_array[i].m_stride << " "
471  << m_array[i].m_is_valid << " "
472  << m_array[i].m_use_time << std::endl;
473  }
474 }
475 
476 Addr
478 {
479  return mbits<Addr>(addr, 63, m_page_shift);
480 }
uint32_t m_negative_filter_index
a round robin pointer into the negative filter group
Definition: Prefetcher.hh:173
#define DPRINTF(x,...)
Definition: trace.hh:229
Stats::Scalar numPartialHits
Count of partial successful prefetches.
Definition: Prefetcher.hh:209
int * m_nonunit_stride
An array of strides (in # of cache lines) for the filter entries.
Definition: Prefetcher.hh:182
Bitfield< 30, 0 > index
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:83
uint32_t getLRUindex(void)
Returns an unused stream buffer (or if all are used, returns the least recently used (accessed) strea...
Definition: Prefetcher.cc:262
std::bitset< MAX_PF_INFLIGHT > requestIssued
Bitset for tracking prefetches for which addresses have been issued, which ones have completed...
Definition: Prefetcher.hh:77
Stats::Scalar numMissedPrefetchedBlocks
Count of misses incurred for blocks that were prefetched.
Definition: Prefetcher.hh:213
Bitfield< 7 > i
Stats::Scalar numMissObserved
Count of accesses to the prefetcher.
Definition: Prefetcher.hh:197
Bitfield< 21, 20 > stride
const Addr m_page_shift
Definition: Prefetcher.hh:194
void observePfHit(Addr address)
Implement the prefetch hit(miss) callback interface.
Definition: Prefetcher.cc:216
#define MAX_PF_INFLIGHT
Definition: Prefetcher.hh:46
ip6_addr_t addr
Definition: inet.hh:335
virtual void enqueuePrefetch(const Addr &, const RubyRequestType &)
Function for enqueuing a prefetch request.
virtual void regStats()
Callback to set stat parameters.
Definition: group.cc:66
RubyRequestType m_type
L1D prefetches loads and stores.
Definition: Prefetcher.hh:73
Stats::Scalar numHits
Count of successful prefetches.
Definition: Prefetcher.hh:207
void clearNonunitEntry(uint32_t index)
clear a non-unit stride prefetcher entry
Definition: Prefetcher.cc:281
Prefetcher(const Params *p)
Definition: Prefetcher.cc:42
int m_stride
stride distance to get next address from
Definition: Prefetcher.hh:64
std::vector< Addr > m_negative_filter
a negative nit stride filter array: helps reduce BW requirement of prefetching
Definition: Prefetcher.hh:171
uint32_t m_train_misses
number of misses I must see before allocating a stream
Definition: Prefetcher.hh:152
Stats::Scalar numPrefetchAccepted
Count of prefetch requests accepted.
Definition: Prefetcher.hh:203
uint32_t m_unit_filter_index
a round robin pointer into the unit filter group
Definition: Prefetcher.hh:164
uint8_t type
Definition: inet.hh:333
std::vector< Addr > m_nonunit_filter
a non-unit stride filter array: helps reduce BW requirement of prefetching
Definition: Prefetcher.hh:180
bool m_is_valid
valid bit for each stream
Definition: Prefetcher.hh:70
uint32_t m_num_nonunit_filters
number of non-stride filters
Definition: Prefetcher.hh:158
bool accessNonunitFilter(Addr address, int *stride, bool &alloc)
access a unit stride filter to determine if there is a hit
Definition: Prefetcher.cc:381
Bitfield< 23 > k
Definition: dt_constants.hh:80
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Stats::Scalar numPagesCrossed
Count of pages crossed.
Definition: Prefetcher.hh:211
uint32_t * m_nonunit_hit
An array used to count the of times particular filter entries have been hit.
Definition: Prefetcher.hh:185
void initializeStream(Addr address, int stride, uint32_t index, const RubyRequestType &type)
allocate a new stream buffer at a specific index
Definition: Prefetcher.cc:289
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
virtual const std::string name() const
Definition: sim_object.hh:120
bool m_prefetch_cross_pages
Used for allowing prefetches across pages.
Definition: Prefetcher.hh:190
Addr makeLineAddress(Addr addr)
Definition: Address.cc:54
void regStats()
Callback to set stat parameters.
Definition: Prefetcher.cc:89
std::vector< PrefetchEntry > m_array
an array of the active prefetch streams
Definition: Prefetcher.hh:149
Addr m_address
The base address for the stream prefetch.
Definition: Prefetcher.hh:61
Bitfield< 24 > j
void issueNextPrefetch(Addr address, PrefetchEntry *stream)
Definition: Prefetcher.cc:224
Derived & name(const std::string &name)
Set the name and marks this stat to print at the end of simulation.
Definition: statistics.hh:279
uint32_t m_nonunit_index
a round robin pointer into the unit filter group
Definition: Prefetcher.hh:187
bool accessUnitFilter(std::vector< Addr > &filter_table, uint32_t *hit_table, uint32_t &index, Addr address, int stride, bool &alloc)
access a unit stride filter to determine if there is a hit
Definition: Prefetcher.cc:348
void print(std::ostream &out) const
Print out some statistics.
Definition: Prefetcher.cc:444
uint32_t m_num_unit_filters
number of stride filters
Definition: Prefetcher.hh:156
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: Prefetcher.cc:330
void observeMiss(Addr address, const RubyRequestType &type)
Observe a memory miss from the cache.
Definition: Prefetcher.cc:140
Stats::Scalar numPrefetchRequested
Count of prefetch requests made.
Definition: Prefetcher.hh:201
std::bitset< MAX_PF_INFLIGHT > requestCompleted
Definition: Prefetcher.hh:78
uint32_t * m_unit_filter_hit
An array used to count the of times particular filter entries have been hit.
Definition: Prefetcher.hh:167
Stats::Scalar numAllocatedStreams
Count of prefetch streams allocated.
Definition: Prefetcher.hh:199
Derived & desc(const std::string &_desc)
Set the description and marks this stat to print at the end of simulation.
Definition: statistics.hh:312
PrefetcherParams Params
Definition: Prefetcher.hh:84
uint32_t m_num_streams
number of prefetch streams available
Definition: Prefetcher.hh:147
uint32_t * m_negative_filter_hit
An array used to count the of times particular filter entries have been hit.
Definition: Prefetcher.hh:176
uint32_t m_num_startup_pfs
number of initial prefetches to startup a stream
Definition: Prefetcher.hh:154
Bitfield< 0 > p
Addr makeNextStrideAddress(Addr addr, int stride)
Definition: Address.cc:61
static uint32_t getBlockSizeBytes()
Definition: RubySystem.hh:59
AbstractController * m_controller
Definition: Prefetcher.hh:192
Abstract superclass for simulation objects.
Definition: sim_object.hh:96
void observePfMiss(Addr address)
Definition: Prefetcher.cc:208
Stats::Scalar numDroppedPrefetches
Count of prefetches dropped.
Definition: Prefetcher.hh:205
Addr pageAddress(Addr addr) const
determine the page aligned address
Definition: Prefetcher.cc:477
std::vector< Addr > m_unit_filter
a unit stride filter array: helps reduce BW requirement of prefetching
Definition: Prefetcher.hh:162
Cycles m_use_time
the last time that any prefetched request was used
Definition: Prefetcher.hh:67

Generated on Fri Feb 28 2020 16:27:02 for gem5 by doxygen 1.8.13