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