gem5  v22.1.0.0
fa_lru.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 Inria
3  * Copyright (c) 2013,2016-2018 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) 2003-2005 The Regents of The University of Michigan
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 
47 #include "mem/cache/tags/fa_lru.hh"
48 
49 #include <cassert>
50 #include <sstream>
51 
52 #include "base/compiler.hh"
53 #include "base/intmath.hh"
54 #include "base/logging.hh"
55 #include "mem/cache/base.hh"
57 
58 namespace gem5
59 {
60 
61 std::string
63 {
64  return csprintf("%s inCachesMask: %#x", CacheBlk::print(), inCachesMask);
65 }
66 
68  : BaseTags(p),
69 
70  cacheTracking(p.min_tracked_cache_size, size, blkSize, this)
71 {
72  if (!isPowerOf2(blkSize))
73  fatal("cache block size (in bytes) `%d' must be a power of two",
74  blkSize);
75  if (!isPowerOf2(size))
76  fatal("Cache Size must be power of 2 for now");
77 
78  blks = new FALRUBlk[numBlocks];
79 }
80 
82 {
83  delete[] blks;
84 }
85 
86 void
88 {
89  head = &(blks[0]);
90  head->prev = nullptr;
91  head->next = &(blks[1]);
92  head->setPosition(0, 0);
93  head->data = &dataBlks[0];
94 
95  for (unsigned i = 1; i < numBlocks - 1; i++) {
96  blks[i].prev = &(blks[i-1]);
97  blks[i].next = &(blks[i+1]);
98  blks[i].setPosition(0, i);
99 
100  // Associate a data chunk to the block
101  blks[i].data = &dataBlks[blkSize*i];
102  }
103 
104  tail = &(blks[numBlocks - 1]);
105  tail->prev = &(blks[numBlocks - 2]);
106  tail->next = nullptr;
107  tail->setPosition(0, numBlocks - 1);
108  tail->data = &dataBlks[(numBlocks - 1) * blkSize];
109 
111 }
112 
113 void
115 {
116  // Erase block entry reference in the hash table
117  [[maybe_unused]] auto num_erased =
118  tagHash.erase(std::make_pair(blk->getTag(), blk->isSecure()));
119 
120  // Sanity check; only one block reference should be erased
121  assert(num_erased == 1);
122 
123  // Invalidate block entry. Must be done after the hash is erased
125 
126  // Decrease the number of tags in use
127  stats.tagsInUse--;
128 
129  // Move the block to the tail to make it the next victim
130  moveToTail((FALRUBlk*)blk);
131 }
132 
133 CacheBlk*
135 {
136  return accessBlock(pkt, lat, 0);
137 }
138 
139 CacheBlk*
141  CachesMask *in_caches_mask)
142 {
143  CachesMask mask = 0;
144  FALRUBlk* blk =
145  static_cast<FALRUBlk*>(findBlock(pkt->getAddr(), pkt->isSecure()));
146 
147  // If a cache hit
148  if (blk && blk->isValid()) {
149  mask = blk->inCachesMask;
150 
151  moveToHead(blk);
152  }
153 
154  if (in_caches_mask) {
155  *in_caches_mask = mask;
156  }
157 
159 
160  // The tag lookup latency is the same for a hit or a miss
161  lat = lookupLatency;
162 
163  return blk;
164 }
165 
166 CacheBlk*
167 FALRU::findBlock(Addr addr, bool is_secure) const
168 {
169  FALRUBlk* blk = nullptr;
170 
171  Addr tag = extractTag(addr);
172  auto iter = tagHash.find(std::make_pair(tag, is_secure));
173  if (iter != tagHash.end()) {
174  blk = (*iter).second;
175  }
176 
177  if (blk && blk->isValid()) {
178  assert(blk->getTag() == tag);
179  assert(blk->isSecure() == is_secure);
180  }
181 
182  return blk;
183 }
184 
186 FALRU::findBlockBySetAndWay(int set, int way) const
187 {
188  assert(set == 0);
189  return &blks[way];
190 }
191 
192 CacheBlk*
193 FALRU::findVictim(Addr addr, const bool is_secure, const std::size_t size,
194  std::vector<CacheBlk*>& evict_blks)
195 {
196  // The victim is always stored on the tail for the FALRU
197  FALRUBlk* victim = tail;
198 
199  // There is only one eviction for this replacement
200  evict_blks.push_back(victim);
201 
202  return victim;
203 }
204 
205 void
207 {
208  FALRUBlk* falruBlk = static_cast<FALRUBlk*>(blk);
209 
210  // Make sure block is not present in the cache
211  assert(falruBlk->inCachesMask == 0);
212 
213  // Do common block insertion functionality
214  BaseTags::insertBlock(pkt, blk);
215 
216  // Increment tag counter
217  stats.tagsInUse++;
218 
219  // New block is the MRU
220  moveToHead(falruBlk);
221 
222  // Insert new block in the hash table
223  tagHash[std::make_pair(blk->getTag(), blk->isSecure())] = falruBlk;
224 }
225 
226 void
227 FALRU::moveBlock(CacheBlk *src_blk, CacheBlk *dest_blk)
228 {
229  panic("Moving blocks in FALRU has not been implemented");
230 }
231 
232 void
234 {
235  // If block is not already head, do the moving
236  if (blk != head) {
238  // If block is tail, set previous block as new tail
239  if (blk == tail){
240  assert(blk->next == nullptr);
241  tail = blk->prev;
242  tail->next = nullptr;
243  // Inform block's surrounding blocks that it has been moved
244  } else {
245  blk->prev->next = blk->next;
246  blk->next->prev = blk->prev;
247  }
248 
249  // Swap pointers
250  blk->next = head;
251  blk->prev = nullptr;
252  head->prev = blk;
253  head = blk;
254 
256  }
257 }
258 
259 void
261 {
262  // If block is not already tail, do the moving
263  if (blk != tail) {
265  // If block is head, set next block as new head
266  if (blk == head){
267  assert(blk->prev == nullptr);
268  head = blk->next;
269  head->prev = nullptr;
270  // Inform block's surrounding blocks that it has been moved
271  } else {
272  blk->prev->next = blk->next;
273  blk->next->prev = blk->prev;
274  }
275 
276  // Swap pointers
277  blk->prev = tail;
278  blk->next = nullptr;
279  tail->next = blk;
280  tail = blk;
281 
283  }
284 }
285 
286 void
287 printSize(std::ostream &stream, size_t size)
288 {
289  static const char *SIZES[] = { "B", "kB", "MB", "GB", "TB", "ZB" };
290  int div = 0;
291  while (size >= 1024 && div < (sizeof SIZES / sizeof *SIZES)) {
292  div++;
293  size >>= 10;
294  }
295  stream << size << SIZES[div];
296 }
297 
298 FALRU::CacheTracking::CacheTracking(unsigned min_size, unsigned max_size,
299  unsigned block_size, statistics::Group *parent)
300  : statistics::Group(parent),
301  blkSize(block_size),
302  minTrackedSize(min_size),
303  numTrackedCaches(max_size > min_size ?
304  floorLog2(max_size) - floorLog2(min_size) : 0),
305  inAllCachesMask(mask(numTrackedCaches)),
306  boundaries(numTrackedCaches),
307  ADD_STAT(hits, statistics::units::Count::get(),
308  "The number of hits in each cache size."),
309  ADD_STAT(misses, statistics::units::Count::get(),
310  "The number of misses in each cache size."),
311  ADD_STAT(accesses, statistics::units::Count::get(),
312  "The number of accesses to the FA LRU cache.")
313 {
314  fatal_if(numTrackedCaches > sizeof(CachesMask) * 8,
315  "Not enough bits (%s) in type CachesMask type to keep "
316  "track of %d caches\n", sizeof(CachesMask),
318 
319  hits
320  .init(numTrackedCaches + 1);
321  misses
322  .init(numTrackedCaches + 1);
323 
324  for (unsigned i = 0; i < numTrackedCaches + 1; ++i) {
325  std::stringstream size_str;
326  printSize(size_str, minTrackedSize << i);
327  hits.subname(i, size_str.str());
328  hits.subdesc(i, "Hits in a " + size_str.str() + " cache");
329  misses.subname(i, size_str.str());
330  misses.subdesc(i, "Misses in a " + size_str.str() + " cache");
331  }
332 }
333 
334 void
336 {
337 #ifdef FALRU_DEBUG
338  const FALRUBlk* blk = head;
339  unsigned curr_size = 0;
340  unsigned tracked_cache_size = minTrackedSize;
341  CachesMask in_caches_mask = inAllCachesMask;
342  int j = 0;
343 
344  while (blk) {
345  panic_if(blk->inCachesMask != in_caches_mask, "Expected cache mask "
346  "%x found %x", blk->inCachesMask, in_caches_mask);
347 
348  curr_size += blkSize;
349  if (curr_size == tracked_cache_size && blk != tail) {
350  panic_if(boundaries[j] != blk, "Unexpected boundary for the %d-th "
351  "cache", j);
352  tracked_cache_size <<= 1;
353  // from this point, blocks fit only in the larger caches
354  in_caches_mask &= ~(1U << j);
355  ++j;
356  }
357  blk = blk->next;
358  }
359 #endif // FALRU_DEBUG
360 }
361 
362 void
364 {
365  // early exit if we are not tracking any extra caches
366  FALRUBlk* blk = numTrackedCaches ? head : nullptr;
367  unsigned curr_size = 0;
368  unsigned tracked_cache_size = minTrackedSize;
369  CachesMask in_caches_mask = inAllCachesMask;
370  int j = 0;
371 
372  while (blk) {
373  blk->inCachesMask = in_caches_mask;
374 
375  curr_size += blkSize;
376  if (curr_size == tracked_cache_size && blk != tail) {
377  boundaries[j] = blk;
378 
379  tracked_cache_size <<= 1;
380  // from this point, blocks fit only in the larger caches
381  in_caches_mask &= ~(1U << j);
382  ++j;
383  }
384  blk = blk->next;
385  }
386 }
387 
388 
389 void
391 {
392  // Get the mask of all caches, in which the block didn't fit
393  // before moving it to the head
394  CachesMask update_caches_mask = inAllCachesMask ^ blk->inCachesMask;
395 
396  for (int i = 0; i < numTrackedCaches; i++) {
397  CachesMask current_cache_mask = 1U << i;
398  if (current_cache_mask & update_caches_mask) {
399  // if the ith cache didn't fit the block (before it is moved to
400  // the head), move the ith boundary 1 block closer to the
401  // MRU
402  boundaries[i]->inCachesMask &= ~current_cache_mask;
403  boundaries[i] = boundaries[i]->prev;
404  } else if (boundaries[i] == blk) {
405  // Make sure the boundary doesn't point to the block
406  // we are about to move
407  boundaries[i] = blk->prev;
408  }
409  }
410 
411  // Make block reside in all caches
412  blk->inCachesMask = inAllCachesMask;
413 }
414 
415 void
417 {
418  CachesMask update_caches_mask = blk->inCachesMask;
419 
420  for (int i = 0; i < numTrackedCaches; i++) {
421  CachesMask current_cache_mask = 1U << i;
422  if (current_cache_mask & update_caches_mask) {
423  // if the ith cache fitted the block (before it is moved to
424  // the tail), move the ith boundary 1 block closer to the
425  // LRU
426  boundaries[i] = boundaries[i]->next;
427  if (boundaries[i] == blk) {
428  // Make sure the boundary doesn't point to the block
429  // we are about to move
430  boundaries[i] = blk->next;
431  }
432  boundaries[i]->inCachesMask |= current_cache_mask;
433  }
434  }
435 
436  // The block now fits only in the actual cache
437  blk->inCachesMask = 0;
438 }
439 
440 void
442 {
443  for (int i = 0; i < numTrackedCaches; i++) {
444  if (blk && ((1U << i) & blk->inCachesMask)) {
445  hits[i]++;
446  } else {
447  misses[i]++;
448  }
449  }
450 
451  // Record stats for the actual cache too
452  if (blk && blk->isValid()) {
453  hits[numTrackedCaches]++;
454  } else {
455  misses[numTrackedCaches]++;
456  }
457 
458  accesses++;
459 }
460 
461 } // namespace gem5
A common base class of Cache tagstore objects.
Definition: base.hh:74
virtual void insertBlock(const PacketPtr pkt, CacheBlk *blk)
Insert the new block into the cache and update stats.
Definition: base.cc:102
const unsigned size
The size of the cache.
Definition: base.hh:81
const unsigned numBlocks
the number of blocks in the cache
Definition: base.hh:100
virtual void invalidate(CacheBlk *blk)
This function updates the tags when a block is invalidated.
Definition: base.hh:254
gem5::BaseTags::BaseTagStats stats
BaseTagsParams Params
Definition: base.hh:161
std::unique_ptr< uint8_t[]> dataBlks
The data blocks, 1 per cache block.
Definition: base.hh:103
const Cycles lookupLatency
The tag lookup latency of the cache.
Definition: base.hh:83
const unsigned blkSize
The block size of the cache.
Definition: base.hh:77
A Basic Cache block.
Definition: cache_blk.hh:71
std::string print() const override
Pretty-print tag, set and way, and interpret state bits to readable form including mapping to a MOESI...
Definition: cache_blk.hh:364
uint8_t * data
Contains a copy of the data in this block for easy access.
Definition: cache_blk.hh:103
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
A fully associative cache block.
Definition: fa_lru.hh:85
FALRUBlk * next
The next block in LRU order.
Definition: fa_lru.hh:92
FALRUBlk * prev
The previous block in LRU order.
Definition: fa_lru.hh:90
std::string print() const override
Pretty-print inCachesMask and other CacheBlk information.
Definition: fa_lru.cc:62
CachesMask inCachesMask
A bit mask of the caches that fit this block.
Definition: fa_lru.hh:95
void check(const FALRUBlk *head, const FALRUBlk *tail) const
Check that the tracking mechanism is in consistent state.
Definition: fa_lru.cc:335
void recordAccess(FALRUBlk *blk)
Notify of a block access.
Definition: fa_lru.cc:441
void init(FALRUBlk *head, FALRUBlk *tail)
Initialiaze cache blocks and the tracking mechanism.
Definition: fa_lru.cc:363
void moveBlockToHead(FALRUBlk *blk)
Update boundaries as a block will be moved to the MRU.
Definition: fa_lru.cc:390
void moveBlockToTail(FALRUBlk *blk)
Update boundaries as a block will be moved to the LRU.
Definition: fa_lru.cc:416
const unsigned minTrackedSize
The smallest cache we are tracking.
Definition: fa_lru.hh:344
CacheTracking(unsigned min_size, unsigned max_size, unsigned block_size, statistics::Group *parent)
Definition: fa_lru.cc:298
const int numTrackedCaches
The number of different size caches being tracked.
Definition: fa_lru.hh:346
void moveToTail(FALRUBlk *blk)
Move a cache block to the LRU position.
Definition: fa_lru.cc:260
CacheBlk * accessBlock(const PacketPtr pkt, Cycles &lat, CachesMask *in_cache_mask)
Access block and update replacement data.
Definition: fa_lru.cc:140
TagHash tagHash
The address hash table.
Definition: fa_lru.hh:137
Addr extractTag(Addr addr) const override
Generate the tag from the addres.
Definition: fa_lru.hh:240
FALRU(const Params &p)
Construct and initialize this cache tagstore.
Definition: fa_lru.cc:67
ReplaceableEntry * findBlockBySetAndWay(int set, int way) const override
Find a block given set and way.
Definition: fa_lru.cc:186
void moveBlock(CacheBlk *src_blk, CacheBlk *dest_blk) override
Move a block's metadata to another location decided by the replacement policy.
Definition: fa_lru.cc:227
void invalidate(CacheBlk *blk) override
Invalidate a cache block.
Definition: fa_lru.cc:114
void moveToHead(FALRUBlk *blk)
Move a cache block to the MRU position.
Definition: fa_lru.cc:233
CacheBlk * findVictim(Addr addr, const bool is_secure, const std::size_t size, std::vector< CacheBlk * > &evict_blks) override
Find replacement victim based on address.
Definition: fa_lru.cc:193
CacheBlk * findBlock(Addr addr, bool is_secure) const override
Find the block in the cache, do not update the replacement data.
Definition: fa_lru.cc:167
CacheTracking cacheTracking
Definition: fa_lru.hh:371
void tagsInit() override
Initialize blocks as FALRUBlk instances.
Definition: fa_lru.cc:87
FALRUBlk * tail
The LRU block.
Definition: fa_lru.hh:122
FALRUBlk * head
The MRU block.
Definition: fa_lru.hh:120
void insertBlock(const PacketPtr pkt, CacheBlk *blk) override
Insert the new block into the cache and update replacement data.
Definition: fa_lru.cc:206
FALRUBlk * blks
The cache blocks.
Definition: fa_lru.hh:117
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
bool isSecure() const
Definition: packet.hh:834
Addr getAddr() const
Definition: packet.hh:805
A replaceable entry is a basic entry in a 2d table-like structure that needs to have replacement func...
virtual void setPosition(const uint32_t set, const uint32_t way)
Set both the set and way.
virtual bool isValid() const
Checks if the entry is valid.
Definition: tagged_entry.hh:57
bool isSecure() const
Check if this block holds data from the secure memory space.
Definition: tagged_entry.hh:64
virtual Addr getTag() const
Get tag associated to this block.
Definition: tagged_entry.hh:71
Derived & subname(off_type index, const std::string &name)
Set the subfield name for the given index, and marks this stat to print at the end of simulation.
Definition: statistics.hh:402
Derived & subdesc(off_type index, const std::string &desc)
Set the subfield description for the given index and marks this stat to print at the end of simulatio...
Definition: statistics.hh:426
Statistics container.
Definition: group.hh:94
Derived & init(size_type size)
Set this vector to have the given size.
Definition: statistics.hh:1040
STL vector class.
Definition: stl.hh:37
Declaration of a fully associative LRU tag store.
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition: group.hh:75
statistics::Vector hits
Hits in each cache.
Definition: fa_lru.hh:361
statistics::Vector misses
Misses in each cache.
Definition: fa_lru.hh:363
static constexpr std::enable_if_t< std::is_integral_v< T >, int > floorLog2(T x)
Definition: intmath.hh:59
static constexpr bool isPowerOf2(const T &n)
Definition: intmath.hh:98
constexpr uint64_t mask(unsigned nbits)
Generate a 64-bit mask of 'nbits' 1s, right justified.
Definition: bitfield.hh:63
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:226
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:204
Declares a basic cache interface BaseCache.
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 12, 11 > set
Definition: misc_types.hh:709
Bitfield< 24 > j
Definition: misc_types.hh:57
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 3 > addr
Definition: types.hh:84
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
uint32_t CachesMask
Definition: fa_lru.hh:73
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
void printSize(std::ostream &stream, size_t size)
Definition: fa_lru.cc:287
statistics::Average tagsInUse
Per tick average of the number of tags that hold valid data.
Definition: base.hh:118

Generated on Wed Dec 21 2022 10:22:37 for gem5 by doxygen 1.9.1