Fix a bug to handle the fact that a CPU can send Functional accesses while a sendTimi...
[gem5.git] / src / mem / cache / tags / split.cc
1 /*
2 * Copyright (c) 2004-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: Lisa Hsu
29 */
30
31 /**
32 * @file
33 * Definitions of split cache tag store.
34 */
35
36 #include <string>
37 #include <iostream>
38 #include <fstream>
39
40 #include "base/cprintf.hh"
41 #include "base/intmath.hh"
42 #include "base/output.hh"
43 #include "base/trace.hh"
44 #include "mem/cache/base_cache.hh"
45 #include "mem/cache/tags/split.hh"
46 #include "mem/cache/tags/split_lifo.hh"
47 #include "mem/cache/tags/split_lru.hh"
48
49
50 using namespace std;
51 using namespace TheISA;
52
53 // create and initialize a partitioned cache structure
54 Split::Split(int _numSets, int _blkSize, int total_ways, int LRU1_assoc,
55 bool _lifo, bool _two_queue, int _hit_latency) :
56 numSets(_numSets), blkSize(_blkSize), lifo(_lifo), hitLatency(_hit_latency)
57 {
58 DPRINTF(Split, "new split cache!!\n");
59
60 DPRINTF(Split, "lru has %d numSets, %d blkSize, %d assoc, and %d hit_latency\n",
61 numSets, blkSize, LRU1_assoc, hitLatency);
62
63 lru = new SplitLRU(_numSets, _blkSize, LRU1_assoc, _hit_latency, 1);
64
65 if (total_ways - LRU1_assoc == 0) {
66 lifo_net = NULL;
67 lru_net = NULL;
68 } else {
69 if (lifo) {
70 DPRINTF(Split, "Other partition is a LIFO with size %d in bytes. it gets %d ways\n",
71 (total_ways - LRU1_assoc)*_numSets*_blkSize, (total_ways - LRU1_assoc));
72 lifo_net = new SplitLIFO(_blkSize, (total_ways - LRU1_assoc)*_numSets*_blkSize,
73 (total_ways - LRU1_assoc), _hit_latency, _two_queue, 2);
74 lru_net = NULL;
75 }
76 else {
77 DPRINTF(Split, "other LRU gets %d ways\n", total_ways - LRU1_assoc);
78 lru_net = new SplitLRU(_numSets, _blkSize, total_ways - LRU1_assoc, _hit_latency, 2);
79 lifo_net = NULL;
80 }
81 }
82
83 blkMask = blkSize - 1;
84
85 if (!isPowerOf2(total_ways))
86 warn("total cache ways/columns %d should be power of 2",
87 total_ways);
88
89 warmedUp = false;
90 /** @todo Make warmup percentage a parameter. */
91 warmupBound = numSets * total_ways;
92
93 }
94
95 Split::~Split()
96 {
97 delete lru;
98 if (lifo)
99 delete lifo_net;
100 else
101 delete lru_net;
102 }
103
104 void
105 Split::regStats(const string &name)
106 {
107 using namespace Stats;
108
109 BaseTags::regStats(name);
110
111 usedEvictDist.init(0,3000,40);
112 unusedEvictDist.init(0,3000,40);
113 useByCPUCycleDist.init(0,35,1);
114
115 nic_repl
116 .name(name + ".nic_repl")
117 .desc("number of replacements in the nic partition")
118 .precision(0)
119 ;
120
121 cpu_repl
122 .name(name + ".cpu_repl")
123 .desc("number of replacements in the cpu partition")
124 .precision(0)
125 ;
126
127 lru->regStats(name + ".lru");
128
129 if (lifo && lifo_net) {
130 lifo_net->regStats(name + ".lifo_net");
131 } else if (lru_net) {
132 lru_net->regStats(name + ".lru_net");
133 }
134
135 nicUsedWhenEvicted
136 .name(name + ".nicUsedWhenEvicted")
137 .desc("number of NIC blks that were used before evicted")
138 ;
139
140 nicUsedTotLatency
141 .name(name + ".nicUsedTotLatency")
142 .desc("total cycles before eviction of used NIC blks")
143 ;
144
145 nicUsedTotEvicted
146 .name(name + ".nicUsedTotEvicted")
147 .desc("total number of used NIC blks evicted")
148 ;
149
150 nicUsedAvgLatency
151 .name(name + ".nicUsedAvgLatency")
152 .desc("avg number of cycles a used NIC blk is in cache")
153 .precision(0)
154 ;
155 nicUsedAvgLatency = nicUsedTotLatency / nicUsedTotEvicted;
156
157 usedEvictDist
158 .name(name + ".usedEvictDist")
159 .desc("distribution of used NIC blk eviction times")
160 .flags(pdf | cdf)
161 ;
162
163 nicUnusedWhenEvicted
164 .name(name + ".nicUnusedWhenEvicted")
165 .desc("number of NIC blks that were unused when evicted")
166 ;
167
168 nicUnusedTotLatency
169 .name(name + ".nicUnusedTotLatency")
170 .desc("total cycles before eviction of unused NIC blks")
171 ;
172
173 nicUnusedTotEvicted
174 .name(name + ".nicUnusedTotEvicted")
175 .desc("total number of unused NIC blks evicted")
176 ;
177
178 nicUnusedAvgLatency
179 .name(name + ".nicUnusedAvgLatency")
180 .desc("avg number of cycles an unused NIC blk is in cache")
181 .precision(0)
182 ;
183 nicUnusedAvgLatency = nicUnusedTotLatency / nicUnusedTotEvicted;
184
185 unusedEvictDist
186 .name(name + ".unusedEvictDist")
187 .desc("distribution of unused NIC blk eviction times")
188 .flags(pdf | cdf)
189 ;
190
191 nicUseByCPUCycleTotal
192 .name(name + ".nicUseByCPUCycleTotal")
193 .desc("total latency of NIC blks til usage time")
194 ;
195
196 nicBlksUsedByCPU
197 .name(name + ".nicBlksUsedByCPU")
198 .desc("total number of NIC blks used")
199 ;
200
201 nicAvgUsageByCPULatency
202 .name(name + ".nicAvgUsageByCPULatency")
203 .desc("average number of cycles before a NIC blk that is used gets used")
204 .precision(0)
205 ;
206 nicAvgUsageByCPULatency = nicUseByCPUCycleTotal / nicBlksUsedByCPU;
207
208 useByCPUCycleDist
209 .name(name + ".useByCPUCycleDist")
210 .desc("the distribution of cycle time in cache before NIC blk is used")
211 .flags(pdf | cdf)
212 ;
213
214 cpuUsedBlks
215 .name(name + ".cpuUsedBlks")
216 .desc("number of cpu blks that were used before evicted")
217 ;
218
219 cpuUnusedBlks
220 .name(name + ".cpuUnusedBlks")
221 .desc("number of cpu blks that were unused before evicted")
222 ;
223
224 nicAvgLatency
225 .name(name + ".nicAvgLatency")
226 .desc("avg number of cycles a NIC blk is in cache before evicted")
227 .precision(0)
228 ;
229 nicAvgLatency = (nicUnusedTotLatency + nicUsedTotLatency) /
230 (nicUnusedTotEvicted + nicUsedTotEvicted);
231
232 NR_CP_hits
233 .name(name + ".NR_CP_hits")
234 .desc("NIC requests hitting in CPU Partition")
235 ;
236
237 NR_NP_hits
238 .name(name + ".NR_NP_hits")
239 .desc("NIC requests hitting in NIC Partition")
240 ;
241
242 CR_CP_hits
243 .name(name + ".CR_CP_hits")
244 .desc("CPU requests hitting in CPU partition")
245 ;
246
247 CR_NP_hits
248 .name(name + ".CR_NP_hits")
249 .desc("CPU requests hitting in NIC partition")
250 ;
251
252 }
253
254 // probe cache for presence of given block.
255 bool
256 Split::probe(Addr addr) const
257 {
258 bool success = lru->probe(addr);
259 if (!success) {
260 if (lifo && lifo_net)
261 success = lifo_net->probe(addr);
262 else if (lru_net)
263 success = lru_net->probe(addr);
264 }
265
266 return success;
267 }
268
269 SplitBlk*
270 Split::findBlock(PacketPtr &pkt, int &lat)
271 {
272
273 Addr aligned = blkAlign(pkt->getAddr());
274
275 if (memHash.count(aligned)) {
276 memHash[aligned]++;
277 } else if (pkt->nic_pkt()) {
278 memHash[aligned] = 1;
279 }
280
281 SplitBlk *blk = lru->findBlock(pkt->getAddr(), lat);
282 if (blk) {
283 if (pkt->nic_pkt()) {
284 NR_CP_hits++;
285 } else {
286 CR_CP_hits++;
287 }
288 } else {
289 if (lifo && lifo_net) {
290 blk = lifo_net->findBlock(pkt->getAddr(), lat);
291
292 } else if (lru_net) {
293 blk = lru_net->findBlock(pkt->getAddr(), lat);
294 }
295 if (blk) {
296 if (pkt->nic_pkt()) {
297 NR_NP_hits++;
298 } else {
299 CR_NP_hits++;
300 }
301 }
302 }
303
304 if (blk) {
305 Tick latency = curTick - blk->ts;
306 if (blk->isNIC) {
307 if (!blk->isUsed && !pkt->nic_pkt()) {
308 useByCPUCycleDist.sample(latency);
309 nicUseByCPUCycleTotal += latency;
310 nicBlksUsedByCPU++;
311 }
312 }
313 blk->isUsed = true;
314
315 if (pkt->nic_pkt()) {
316 DPRINTF(Split, "found block in partition %d\n", blk->part);
317 }
318 }
319 return blk;
320 }
321
322 SplitBlk*
323 Split::findBlock(Addr addr, int &lat)
324 {
325 SplitBlk *blk = lru->findBlock(addr, lat);
326 if (!blk) {
327 if (lifo && lifo_net) {
328 blk = lifo_net->findBlock(addr, lat);
329 } else if (lru_net) {
330 blk = lru_net->findBlock(addr, lat);
331 }
332 }
333
334 return blk;
335 }
336
337 SplitBlk*
338 Split::findBlock(Addr addr) const
339 {
340 SplitBlk *blk = lru->findBlock(addr);
341 if (!blk) {
342 if (lifo && lifo_net) {
343 blk = lifo_net->findBlock(addr);
344 } else if (lru_net) {
345 blk = lru_net->findBlock(addr);
346 }
347 }
348
349 return blk;
350 }
351
352 SplitBlk*
353 Split::findReplacement(PacketPtr &pkt, PacketList &writebacks,
354 BlkList &compress_blocks)
355 {
356 SplitBlk *blk;
357
358 if (pkt->nic_pkt()) {
359 DPRINTF(Split, "finding a replacement for nic_req\n");
360 nic_repl++;
361 if (lifo && lifo_net)
362 blk = lifo_net->findReplacement(pkt, writebacks,
363 compress_blocks);
364 else if (lru_net)
365 blk = lru_net->findReplacement(pkt, writebacks,
366 compress_blocks);
367 // in this case, this is an LRU only cache, it's non partitioned
368 else
369 blk = lru->findReplacement(pkt, writebacks, compress_blocks);
370 } else {
371 DPRINTF(Split, "finding replacement for cpu_req\n");
372 blk = lru->findReplacement(pkt, writebacks,
373 compress_blocks);
374 cpu_repl++;
375 }
376
377 Tick latency = curTick - blk->ts;
378 if (blk->isNIC) {
379 if (blk->isUsed) {
380 nicUsedWhenEvicted++;
381 usedEvictDist.sample(latency);
382 nicUsedTotLatency += latency;
383 nicUsedTotEvicted++;
384 } else {
385 nicUnusedWhenEvicted++;
386 unusedEvictDist.sample(latency);
387 nicUnusedTotLatency += latency;
388 nicUnusedTotEvicted++;
389 }
390 } else {
391 if (blk->isUsed) {
392 cpuUsedBlks++;
393 } else {
394 cpuUnusedBlks++;
395 }
396 }
397
398 // blk attributes for the new blk coming IN
399 blk->ts = curTick;
400 blk->isNIC = (pkt->nic_pkt()) ? true : false;
401
402 return blk;
403 }
404
405 void
406 Split::invalidateBlk(Addr addr)
407 {
408 SplitBlk *blk = lru->findBlock(addr);
409 if (!blk) {
410 if (lifo && lifo_net)
411 blk = lifo_net->findBlock(addr);
412 else if (lru_net)
413 blk = lru_net->findBlock(addr);
414
415 if (!blk)
416 return;
417 }
418
419 blk->status = 0;
420 blk->isTouched = false;
421 tagsInUse--;
422 }
423
424 void
425 Split::cleanupRefs()
426 {
427 lru->cleanupRefs();
428 if (lifo && lifo_net)
429 lifo_net->cleanupRefs();
430 else if (lru_net)
431 lru_net->cleanupRefs();
432
433 ofstream memPrint(simout.resolve("memory_footprint.txt").c_str(),
434 ios::trunc);
435
436 // this shouldn't be here but it happens at the end, which is what i want
437 memIter end = memHash.end();
438 for (memIter iter = memHash.begin(); iter != end; ++iter) {
439 ccprintf(memPrint, "%8x\t%d\n", (*iter).first, (*iter).second);
440 }
441 }
442
443 Addr
444 Split::regenerateBlkAddr(Addr tag, int set) const
445 {
446 if (lifo_net)
447 return lifo_net->regenerateBlkAddr(tag, set);
448 else
449 return lru->regenerateBlkAddr(tag, set);
450 }
451
452 Addr
453 Split::extractTag(Addr addr, SplitBlk *blk) const
454 {
455 if (blk->part == 2) {
456 if (lifo_net)
457 return lifo_net->extractTag(addr);
458 else if (lru_net)
459 return lru_net->extractTag(addr);
460 else
461 panic("this shouldn't happen");
462 } else
463 return lru->extractTag(addr);
464 }
465