trace: reimplement the DTRACE function so it doesn't use a vector
[gem5.git] / src / mem / cache / tags / iic.cc
1 /*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
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 * Authors: Erik Hallnor
29 */
30
31 /**
32 * @file
33 * Definitions of the Indirect Index Cache tagstore.
34 */
35
36 #include <algorithm>
37 #include <cmath>
38 #include <string>
39 #include <vector>
40
41 #include "base/intmath.hh"
42 #include "base/trace.hh"
43 #include "debug/Cache.hh"
44 #include "debug/IIC.hh"
45 #include "debug/IICMore.hh"
46 #include "mem/cache/tags/iic.hh"
47 #include "mem/cache/base.hh"
48 #include "sim/core.hh"
49
50 using namespace std;
51
52 /** Track the number of accesses to each cache set. */
53 #define PROFILE_IIC 1
54
55 IIC::IIC(IIC::Params &params) :
56 hashSets(params.numSets), blkSize(params.blkSize), assoc(params.assoc),
57 hitLatency(params.hitLatency), subSize(params.subblockSize),
58 numSub(blkSize/subSize),
59 trivialSize((floorLog2(params.size/subSize)*numSub)/8),
60 tagShift(floorLog2(blkSize)), blkMask(blkSize - 1),
61 subShift(floorLog2(subSize)), subMask(numSub - 1),
62 hashDelay(params.hashDelay),
63 numTags(hashSets * assoc + params.size/blkSize -1),
64 numSecondary(params.size/blkSize),
65 tagNull(numTags),
66 primaryBound(hashSets * assoc)
67 {
68 // Check parameters
69 if (blkSize < 4 || !isPowerOf2(blkSize)) {
70 fatal("Block size must be at least 4 and a power of 2");
71 }
72 if (hashSets <= 0 || !isPowerOf2(hashSets)) {
73 fatal("# of hashsets must be non-zero and a power of 2");
74 }
75 if (assoc <= 0) {
76 fatal("associativity must be greater than zero");
77 }
78 if (hitLatency <= 0) {
79 fatal("access latency must be greater than zero");
80 }
81 if (numSub*subSize != blkSize) {
82 fatal("blocksize must be evenly divisible by subblock size");
83 }
84
85 // debug stuff
86 freeSecond = numSecondary;
87
88 warmedUp = false;
89 warmupBound = params.size/blkSize;
90 numBlocks = params.size/subSize;
91
92 // Replacement Policy Initialization
93 repl = params.rp;
94 repl->setIIC(this);
95
96 //last_miss_time = 0
97
98 // allocate data reference counters
99 dataReferenceCount = new int[numBlocks];
100 memset(dataReferenceCount, 0, numBlocks*sizeof(int));
101
102 // Allocate storage for both internal data and block fast access data.
103 // We allocate it as one large chunk to reduce overhead and to make
104 // deletion easier.
105 unsigned data_index = 0;
106 dataStore = new uint8_t[(numBlocks + numTags) * blkSize];
107 dataBlks = new uint8_t*[numBlocks];
108 for (unsigned i = 0; i < numBlocks; ++i) {
109 dataBlks[i] = &dataStore[data_index];
110 freeDataBlock(i);
111 data_index += subSize;
112 }
113
114 assert(data_index == numBlocks * subSize);
115
116 // allocate and init tag store
117 tagStore = new IICTag[numTags];
118
119 unsigned blkIndex = 0;
120 // allocate and init sets
121 sets = new IICSet[hashSets];
122 for (unsigned i = 0; i < hashSets; ++i) {
123 sets[i].assoc = assoc;
124 sets[i].tags = new IICTag*[assoc];
125 sets[i].chain_ptr = tagNull;
126
127 for (unsigned j = 0; j < assoc; ++j) {
128 IICTag *tag = &tagStore[blkIndex++];
129 tag->chain_ptr = tagNull;
130 tag->data_ptr.resize(numSub);
131 tag->size = blkSize;
132 tag->trivialData = new uint8_t[trivialSize];
133 tag->numData = 0;
134 sets[i].tags[j] = tag;
135 tag->set = i;
136 tag->data = &dataStore[data_index];
137 data_index += blkSize;
138 }
139 }
140
141 assert(blkIndex == primaryBound);
142
143 for (unsigned i = primaryBound; i < tagNull; i++) {
144 tagStore[i].chain_ptr = i+1;
145 //setup data ptrs to subblocks
146 tagStore[i].data_ptr.resize(numSub);
147 tagStore[i].size = blkSize;
148 tagStore[i].trivialData = new uint8_t[trivialSize];
149 tagStore[i].numData = 0;
150 tagStore[i].set = 0;
151 tagStore[i].data = &dataStore[data_index];
152 data_index += blkSize;
153 }
154 freelist = primaryBound;
155 }
156
157 IIC::~IIC()
158 {
159 delete [] dataReferenceCount;
160 delete [] dataStore;
161 delete [] tagStore;
162 delete [] sets;
163 }
164
165 /* register cache stats */
166 void
167 IIC::regStats(const string &name)
168 {
169 using namespace Stats;
170
171 BaseTags::regStats(name);
172
173 hitHashDepth.init(0, 20, 1);
174 missHashDepth.init(0, 20, 1);
175 setAccess.init(0, hashSets, 1);
176
177 /** IIC Statistics */
178 hitHashDepth
179 .name(name + ".hit_hash_depth_dist")
180 .desc("Dist. of Hash lookup depths")
181 .flags(pdf)
182 ;
183
184 missHashDepth
185 .name(name + ".miss_hash_depth_dist")
186 .desc("Dist. of Hash lookup depths")
187 .flags(pdf)
188 ;
189
190 repl->regStats(name);
191
192 if (PROFILE_IIC)
193 setAccess
194 .name(name + ".set_access_dist")
195 .desc("Dist. of Accesses across sets")
196 .flags(pdf)
197 ;
198
199 missDepthTotal
200 .name(name + ".miss_depth_total")
201 .desc("Total of miss depths")
202 ;
203
204 hashMiss
205 .name(name + ".hash_miss")
206 .desc("Total of misses in hash table")
207 ;
208
209 hitDepthTotal
210 .name(name + ".hit_depth_total")
211 .desc("Total of hit depths")
212 ;
213
214 hashHit
215 .name(name + ".hash_hit")
216 .desc("Total of hites in hash table")
217 ;
218 }
219
220
221 IICTag*
222 IIC::accessBlock(Addr addr, int &lat, int context_src)
223 {
224 Addr tag = extractTag(addr);
225 unsigned set = hash(addr);
226 int set_lat;
227
228 unsigned long chain_ptr = tagNull;
229
230 if (PROFILE_IIC)
231 setAccess.sample(set);
232
233 IICTag *tag_ptr = sets[set].findTag(tag, chain_ptr);
234 set_lat = 1;
235 if (tag_ptr == NULL && chain_ptr != tagNull) {
236 int secondary_depth;
237 tag_ptr = secondaryChain(tag, chain_ptr, &secondary_depth);
238 set_lat += secondary_depth;
239 // set depth for statistics fix this later!!! egh
240 sets[set].depth = set_lat;
241
242 if (tag_ptr != NULL) {
243 /* need to move tag into primary table */
244 // need to preserve chain: fix this egh
245 sets[set].tags[assoc-1]->chain_ptr = tag_ptr->chain_ptr;
246 tagSwap(tag_ptr - tagStore, sets[set].tags[assoc-1] - tagStore);
247 tag_ptr = sets[set].findTag(tag, chain_ptr);
248 assert(tag_ptr!=NULL);
249 }
250
251 }
252 set_lat = set_lat * hashDelay + hitLatency;
253 if (tag_ptr != NULL) {
254 // IIC replacement: if this is not the first element of
255 // list, reorder
256 sets[set].moveToHead(tag_ptr);
257
258 hitHashDepth.sample(sets[set].depth);
259 hashHit++;
260 hitDepthTotal += sets[set].depth;
261 tag_ptr->status |= BlkReferenced;
262 lat = set_lat;
263 if (tag_ptr->whenReady > curTick() && tag_ptr->whenReady - curTick() > set_lat) {
264 lat = tag_ptr->whenReady - curTick();
265 }
266
267 tag_ptr->refCount += 1;
268 }
269 else {
270 // fall through: cache block not found, not a hit...
271 missHashDepth.sample(sets[set].depth);
272 hashMiss++;
273 missDepthTotal += sets[set].depth;
274 lat = set_lat;
275 }
276 return tag_ptr;
277 }
278
279
280 IICTag*
281 IIC::findBlock(Addr addr) const
282 {
283 Addr tag = extractTag(addr);
284 unsigned set = hash(addr);
285
286 unsigned long chain_ptr = tagNull;
287
288 IICTag *tag_ptr = sets[set].findTag(tag, chain_ptr);
289 if (tag_ptr == NULL && chain_ptr != tagNull) {
290 int secondary_depth;
291 tag_ptr = secondaryChain(tag, chain_ptr, &secondary_depth);
292 }
293 return tag_ptr;
294 }
295
296
297 IICTag*
298 IIC::findVictim(Addr addr, PacketList &writebacks)
299 {
300 DPRINTF(IIC, "Finding Replacement for %x\n", addr);
301 unsigned set = hash(addr);
302 IICTag *tag_ptr;
303 unsigned long *tmp_data = new unsigned long[numSub];
304
305 // Get a enough subblocks for a full cache line
306 for (unsigned i = 0; i < numSub; ++i){
307 tmp_data[i] = getFreeDataBlock(writebacks);
308 assert(dataReferenceCount[tmp_data[i]]==0);
309 }
310
311 tag_ptr = getFreeTag(set, writebacks);
312
313 tag_ptr->set = set;
314 for (unsigned i = 0; i < numSub; ++i) {
315 tag_ptr->data_ptr[i] = tmp_data[i];
316 dataReferenceCount[tag_ptr->data_ptr[i]]++;
317 }
318 tag_ptr->numData = numSub;
319 assert(tag_ptr - tagStore < primaryBound); // make sure it is in primary
320 tag_ptr->chain_ptr = tagNull;
321 sets[set].moveToHead(tag_ptr);
322 delete [] tmp_data;
323
324 list<unsigned long> tag_indexes;
325 repl->doAdvance(tag_indexes);
326 /*
327 while (!tag_indexes.empty()) {
328 if (!tagStore[tag_indexes.front()].isCompressed()) {
329 compress_blocks.push_back(&tagStore[tag_indexes.front()]);
330 }
331 tag_indexes.pop_front();
332 }
333 */
334
335 tag_ptr->re = (void*)repl->add(tag_ptr-tagStore);
336
337 return tag_ptr;
338 }
339
340 void
341 IIC::insertBlock(Addr addr, BlkType* blk, int context_src)
342 {
343 }
344
345 void
346 IIC::freeReplacementBlock(PacketList & writebacks)
347 {
348 IICTag *tag_ptr;
349 unsigned long data_ptr;
350 /* consult replacement policy */
351 tag_ptr = &tagStore[repl->getRepl()];
352 assert(tag_ptr->isValid());
353
354 DPRINTF(Cache, "Replacing %x in IIC: %s\n",
355 regenerateBlkAddr(tag_ptr->tag,0),
356 tag_ptr->isDirty() ? "writeback" : "clean");
357 /* write back replaced block data */
358 if (tag_ptr && (tag_ptr->isValid())) {
359 replacements[0]++;
360 totalRefs += tag_ptr->refCount;
361 ++sampledRefs;
362 tag_ptr->refCount = 0;
363
364 if (tag_ptr->isDirty()) {
365 /* PacketPtr writeback =
366 buildWritebackReq(regenerateBlkAddr(tag_ptr->tag, 0),
367 tag_ptr->req->asid, tag_ptr->xc, blkSize,
368 tag_ptr->data,
369 tag_ptr->size);
370 */
371 Request *writebackReq = new Request(regenerateBlkAddr(tag_ptr->tag, 0),
372 blkSize, 0);
373 PacketPtr writeback = new Packet(writebackReq, MemCmd::Writeback,
374 -1);
375 writeback->allocate();
376 memcpy(writeback->getPtr<uint8_t>(), tag_ptr->data, blkSize);
377
378 writebacks.push_back(writeback);
379 }
380 }
381
382 // free the data blocks
383 for (int i = 0; i < tag_ptr->numData; ++i) {
384 data_ptr = tag_ptr->data_ptr[i];
385 assert(dataReferenceCount[data_ptr]>0);
386 if (--dataReferenceCount[data_ptr] == 0) {
387 freeDataBlock(data_ptr);
388 }
389 }
390 freeTag(tag_ptr);
391 }
392
393 unsigned long
394 IIC::getFreeDataBlock(PacketList & writebacks)
395 {
396 struct IICTag *tag_ptr;
397 unsigned long data_ptr;
398
399 tag_ptr = NULL;
400 /* find data block */
401 while (blkFreelist.empty()) {
402 freeReplacementBlock(writebacks);
403 }
404
405 data_ptr = blkFreelist.front();
406 blkFreelist.pop_front();
407 DPRINTF(IICMore,"Found free data at %d\n",data_ptr);
408 return data_ptr;
409 }
410
411
412
413 IICTag*
414 IIC::getFreeTag(int set, PacketList & writebacks)
415 {
416 unsigned long tag_index;
417 IICTag *tag_ptr;
418 // Add new tag
419 tag_ptr = sets[set].findFree();
420 // if no free in primary, and secondary exists
421 if (!tag_ptr && numSecondary) {
422 // need to spill a tag into secondary storage
423 while (freelist == tagNull) {
424 // get replacements until one is in secondary
425 freeReplacementBlock(writebacks);
426 }
427
428 tag_index = freelist;
429 freelist = tagStore[freelist].chain_ptr;
430 freeSecond--;
431
432 assert(tag_index != tagNull);
433 tagSwap(tag_index, sets[set].tags[assoc-1] - tagStore);
434 tagStore[tag_index].chain_ptr = sets[set].chain_ptr;
435 sets[set].chain_ptr = tag_index;
436
437 tag_ptr = sets[set].tags[assoc-1];
438 }
439 DPRINTF(IICMore,"Found free tag at %d\n",tag_ptr - tagStore);
440 tagsInUse++;
441 if (!warmedUp && tagsInUse.value() >= warmupBound) {
442 warmedUp = true;
443 warmupCycle = curTick();
444 }
445
446 return tag_ptr;
447 }
448
449 void
450 IIC::freeTag(IICTag *tag_ptr)
451 {
452 unsigned long tag_index, tmp_index;
453 // Fix tag_ptr
454 if (tag_ptr) {
455 // we have a tag to clear
456 DPRINTF(IICMore,"Freeing Tag for %x\n",
457 regenerateBlkAddr(tag_ptr->tag,0));
458 tagsInUse--;
459 tag_ptr->status = 0;
460 tag_ptr->numData = 0;
461 tag_ptr->re = NULL;
462 tag_index = tag_ptr - tagStore;
463 if (tag_index >= primaryBound) {
464 // tag_ptr points to secondary store
465 assert(tag_index < tagNull); // remove this?? egh
466 if (tag_ptr->chain_ptr == tagNull) {
467 // need to fix chain list
468 unsigned tmp_set = hash(tag_ptr->tag << tagShift);
469 if (sets[tmp_set].chain_ptr == tag_index) {
470 sets[tmp_set].chain_ptr = tagNull;
471 } else {
472 tmp_index = sets[tmp_set].chain_ptr;
473 while (tmp_index != tagNull
474 && tagStore[tmp_index].chain_ptr != tag_index) {
475 tmp_index = tagStore[tmp_index].chain_ptr;
476 }
477 assert(tmp_index != tagNull);
478 tagStore[tmp_index].chain_ptr = tagNull;
479 }
480 tag_ptr->chain_ptr = freelist;
481 freelist = tag_index;
482 freeSecond++;
483 } else {
484 // copy next chained entry to this tag location
485 tmp_index = tag_ptr->chain_ptr;
486 tagSwap(tmp_index, tag_index);
487 tagStore[tmp_index].chain_ptr = freelist;
488 freelist = tmp_index;
489 freeSecond++;
490 }
491 } else {
492 // tag_ptr in primary hash table
493 assert(tag_index < primaryBound);
494 tag_ptr->status = 0;
495 unsigned tmp_set = hash(tag_ptr->tag << tagShift);
496 if (sets[tmp_set].chain_ptr != tagNull) { // collapse chain
497 tmp_index = sets[tmp_set].chain_ptr;
498 tagSwap(tag_index, tmp_index);
499 tagStore[tmp_index].chain_ptr = freelist;
500 freelist = tmp_index;
501 freeSecond++;
502 sets[tmp_set].chain_ptr = tag_ptr->chain_ptr;
503 sets[tmp_set].moveToTail(tag_ptr);
504 }
505 }
506 }
507 }
508
509 void
510 IIC::freeDataBlock(unsigned long data_ptr)
511 {
512 assert(dataReferenceCount[data_ptr] == 0);
513 DPRINTF(IICMore, "Freeing data at %d\n", data_ptr);
514 blkFreelist.push_front(data_ptr);
515 }
516
517 /** Use a simple modulo hash. */
518 #define SIMPLE_HASH 0
519
520 unsigned
521 IIC::hash(Addr addr) const {
522 #if SIMPLE_HASH
523 return extractTag(addr) % iic_hash_size;
524 #else
525 Addr tag, mask, x, y;
526 tag = extractTag(addr);
527 mask = hashSets-1; /* assumes iic_hash_size is a power of 2 */
528 x = tag & mask;
529 y = (tag >> (int)(::log((double)hashSets)/::log((double)2))) & mask;
530 assert (x < hashSets && y < hashSets);
531 return x ^ y;
532 #endif
533 }
534
535
536 void
537 IICSet::moveToHead(IICTag *tag)
538 {
539 if (tags[0] == tag)
540 return;
541
542 // write 'next' block into blks[i], moving up from MRU toward LRU
543 // until we overwrite the block we moved to head.
544
545 // start by setting up to write 'blk' into blks[0]
546 int i = 0;
547 IICTag *next = tag;
548
549 do {
550 assert(i < assoc);
551 // swap blks[i] and next
552 IICTag *tmp = tags[i];
553 tags[i] = next;
554 next = tmp;
555 ++i;
556 } while (next != tag);
557 }
558
559 void
560 IICSet::moveToTail(IICTag *tag)
561 {
562 if (tags[assoc-1] == tag)
563 return;
564
565 // write 'next' block into blks[i], moving up from MRU toward LRU
566 // until we overwrite the block we moved to head.
567
568 // start by setting up to write 'blk' into blks[0]
569 int i = assoc - 1;
570 IICTag *next = tag;
571
572 do {
573 assert(i >= 0);
574 // swap blks[i] and next
575 IICTag *tmp = tags[i];
576 tags[i] = next;
577 next = tmp;
578 --i;
579 } while (next != tag);
580 }
581
582 void
583 IIC::tagSwap(unsigned long index1, unsigned long index2)
584 {
585 DPRINTF(IIC,"Swapping tag[%d]=%x for tag[%d]=%x\n",index1,
586 tagStore[index1].tag<<tagShift, index2,
587 tagStore[index2].tag<<tagShift);
588 IICTag tmp_tag;
589 tmp_tag = tagStore[index1];
590 tagStore[index1] = tagStore[index2];
591 tagStore[index2] = tmp_tag;
592 if (tagStore[index1].isValid())
593 repl->fixTag(tagStore[index1].re, index2, index1);
594 if (tagStore[index2].isValid())
595 repl->fixTag(tagStore[index2].re, index1, index2);
596 }
597
598
599 IICTag *
600 IIC::secondaryChain(Addr tag, unsigned long chain_ptr,
601 int *_depth) const
602 {
603 int depth = 0;
604 while (chain_ptr != tagNull) {
605 DPRINTF(IIC,"Searching secondary at %d for %x\n", chain_ptr,
606 tag<<tagShift);
607 if (tagStore[chain_ptr].tag == tag &&
608 (tagStore[chain_ptr].isValid())) {
609 *_depth = depth;
610 return &tagStore[chain_ptr];
611 }
612 depth++;
613 chain_ptr = tagStore[chain_ptr].chain_ptr;
614 }
615 *_depth = depth;
616 return NULL;
617 }
618
619 void
620 IIC::invalidateBlk(IIC::BlkType *tag_ptr)
621 {
622 if (tag_ptr) {
623 for (int i = 0; i < tag_ptr->numData; ++i) {
624 dataReferenceCount[tag_ptr->data_ptr[i]]--;
625 if (dataReferenceCount[tag_ptr->data_ptr[i]] == 0) {
626 freeDataBlock(tag_ptr->data_ptr[i]);
627 }
628 }
629 repl->removeEntry(tag_ptr->re);
630 freeTag(tag_ptr);
631 }
632 }
633
634 void
635 IIC::clearLocks()
636 {
637 for (int i = 0; i < numTags; i++){
638 tagStore[i].clearLoadLocks();
639 }
640 }
641
642 void
643 IIC::cleanupRefs()
644 {
645 for (unsigned i = 0; i < numTags; ++i) {
646 if (tagStore[i].isValid()) {
647 totalRefs += tagStore[i].refCount;
648 ++sampledRefs;
649 }
650 }
651 }