Merge zizzer.eecs.umich.edu:/bk/newmem
[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
270 SplitBlk*
271 Split::findBlock(Addr addr, int &lat)
272 {
273 SplitBlk *blk = lru->findBlock(addr, lat);
274 if (!blk) {
275 if (lifo && lifo_net) {
276 blk = lifo_net->findBlock(addr, lat);
277 } else if (lru_net) {
278 blk = lru_net->findBlock(addr, lat);
279 }
280 }
281
282 return blk;
283 }
284
285 SplitBlk*
286 Split::findBlock(Addr addr) const
287 {
288 SplitBlk *blk = lru->findBlock(addr);
289 if (!blk) {
290 if (lifo && lifo_net) {
291 blk = lifo_net->findBlock(addr);
292 } else if (lru_net) {
293 blk = lru_net->findBlock(addr);
294 }
295 }
296
297 return blk;
298 }
299
300 SplitBlk*
301 Split::findReplacement(PacketPtr &pkt, PacketList &writebacks,
302 BlkList &compress_blocks)
303 {
304 SplitBlk *blk;
305
306 if (pkt->nic_pkt()) {
307 DPRINTF(Split, "finding a replacement for nic_req\n");
308 nic_repl++;
309 if (lifo && lifo_net)
310 blk = lifo_net->findReplacement(pkt, writebacks,
311 compress_blocks);
312 else if (lru_net)
313 blk = lru_net->findReplacement(pkt, writebacks,
314 compress_blocks);
315 // in this case, this is an LRU only cache, it's non partitioned
316 else
317 blk = lru->findReplacement(pkt, writebacks, compress_blocks);
318 } else {
319 DPRINTF(Split, "finding replacement for cpu_req\n");
320 blk = lru->findReplacement(pkt, writebacks,
321 compress_blocks);
322 cpu_repl++;
323 }
324
325 Tick latency = curTick - blk->ts;
326 if (blk->isNIC) {
327 if (blk->isUsed) {
328 nicUsedWhenEvicted++;
329 usedEvictDist.sample(latency);
330 nicUsedTotLatency += latency;
331 nicUsedTotEvicted++;
332 } else {
333 nicUnusedWhenEvicted++;
334 unusedEvictDist.sample(latency);
335 nicUnusedTotLatency += latency;
336 nicUnusedTotEvicted++;
337 }
338 } else {
339 if (blk->isUsed) {
340 cpuUsedBlks++;
341 } else {
342 cpuUnusedBlks++;
343 }
344 }
345
346 // blk attributes for the new blk coming IN
347 blk->ts = curTick;
348 blk->isNIC = (pkt->nic_pkt()) ? true : false;
349
350 return blk;
351 }
352
353 void
354 Split::invalidateBlk(Split::BlkType *blk)
355 {
356 if (!blk) {
357 fatal("FIXME!\n");
358 #if 0
359 if (lifo && lifo_net)
360 blk = lifo_net->findBlock(addr);
361 else if (lru_net)
362 blk = lru_net->findBlock(addr);
363 #endif
364
365 if (!blk)
366 return;
367 }
368
369 blk->status = 0;
370 blk->isTouched = false;
371 tagsInUse--;
372 }
373
374 void
375 Split::cleanupRefs()
376 {
377 lru->cleanupRefs();
378 if (lifo && lifo_net)
379 lifo_net->cleanupRefs();
380 else if (lru_net)
381 lru_net->cleanupRefs();
382
383 ofstream memPrint(simout.resolve("memory_footprint.txt").c_str(),
384 ios::trunc);
385
386 // this shouldn't be here but it happens at the end, which is what i want
387 memIter end = memHash.end();
388 for (memIter iter = memHash.begin(); iter != end; ++iter) {
389 ccprintf(memPrint, "%8x\t%d\n", (*iter).first, (*iter).second);
390 }
391 }
392
393 Addr
394 Split::regenerateBlkAddr(Addr tag, int set) const
395 {
396 if (lifo_net)
397 return lifo_net->regenerateBlkAddr(tag, set);
398 else
399 return lru->regenerateBlkAddr(tag, set);
400 }
401
402 Addr
403 Split::extractTag(Addr addr, SplitBlk *blk) const
404 {
405 if (blk->part == 2) {
406 if (lifo_net)
407 return lifo_net->extractTag(addr);
408 else if (lru_net)
409 return lru_net->extractTag(addr);
410 else
411 panic("this shouldn't happen");
412 } else
413 return lru->extractTag(addr);
414 }
415