2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
33 * Definitions of split cache tag store.
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"
51 using namespace TheISA
;
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
)
58 DPRINTF(Split
, "new split cache!!\n");
60 DPRINTF(Split
, "lru has %d numSets, %d blkSize, %d assoc, and %d hit_latency\n",
61 numSets
, blkSize
, LRU1_assoc
, hitLatency
);
63 lru
= new SplitLRU(_numSets
, _blkSize
, LRU1_assoc
, _hit_latency
, 1);
65 if (total_ways
- LRU1_assoc
== 0) {
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);
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);
83 blkMask
= blkSize
- 1;
85 if (!isPowerOf2(total_ways
))
86 warn("total cache ways/columns %d should be power of 2",
90 /** @todo Make warmup percentage a parameter. */
91 warmupBound
= numSets
* total_ways
;
105 Split::regStats(const string
&name
)
107 using namespace Stats
;
109 BaseTags::regStats(name
);
111 usedEvictDist
.init(0,3000,40);
112 unusedEvictDist
.init(0,3000,40);
113 useByCPUCycleDist
.init(0,35,1);
116 .name(name
+ ".nic_repl")
117 .desc("number of replacements in the nic partition")
122 .name(name
+ ".cpu_repl")
123 .desc("number of replacements in the cpu partition")
127 lru
->regStats(name
+ ".lru");
129 if (lifo
&& lifo_net
) {
130 lifo_net
->regStats(name
+ ".lifo_net");
131 } else if (lru_net
) {
132 lru_net
->regStats(name
+ ".lru_net");
136 .name(name
+ ".nicUsedWhenEvicted")
137 .desc("number of NIC blks that were used before evicted")
141 .name(name
+ ".nicUsedTotLatency")
142 .desc("total cycles before eviction of used NIC blks")
146 .name(name
+ ".nicUsedTotEvicted")
147 .desc("total number of used NIC blks evicted")
151 .name(name
+ ".nicUsedAvgLatency")
152 .desc("avg number of cycles a used NIC blk is in cache")
155 nicUsedAvgLatency
= nicUsedTotLatency
/ nicUsedTotEvicted
;
158 .name(name
+ ".usedEvictDist")
159 .desc("distribution of used NIC blk eviction times")
164 .name(name
+ ".nicUnusedWhenEvicted")
165 .desc("number of NIC blks that were unused when evicted")
169 .name(name
+ ".nicUnusedTotLatency")
170 .desc("total cycles before eviction of unused NIC blks")
174 .name(name
+ ".nicUnusedTotEvicted")
175 .desc("total number of unused NIC blks evicted")
179 .name(name
+ ".nicUnusedAvgLatency")
180 .desc("avg number of cycles an unused NIC blk is in cache")
183 nicUnusedAvgLatency
= nicUnusedTotLatency
/ nicUnusedTotEvicted
;
186 .name(name
+ ".unusedEvictDist")
187 .desc("distribution of unused NIC blk eviction times")
191 nicUseByCPUCycleTotal
192 .name(name
+ ".nicUseByCPUCycleTotal")
193 .desc("total latency of NIC blks til usage time")
197 .name(name
+ ".nicBlksUsedByCPU")
198 .desc("total number of NIC blks used")
201 nicAvgUsageByCPULatency
202 .name(name
+ ".nicAvgUsageByCPULatency")
203 .desc("average number of cycles before a NIC blk that is used gets used")
206 nicAvgUsageByCPULatency
= nicUseByCPUCycleTotal
/ nicBlksUsedByCPU
;
209 .name(name
+ ".useByCPUCycleDist")
210 .desc("the distribution of cycle time in cache before NIC blk is used")
215 .name(name
+ ".cpuUsedBlks")
216 .desc("number of cpu blks that were used before evicted")
220 .name(name
+ ".cpuUnusedBlks")
221 .desc("number of cpu blks that were unused before evicted")
225 .name(name
+ ".nicAvgLatency")
226 .desc("avg number of cycles a NIC blk is in cache before evicted")
229 nicAvgLatency
= (nicUnusedTotLatency
+ nicUsedTotLatency
) /
230 (nicUnusedTotEvicted
+ nicUsedTotEvicted
);
233 .name(name
+ ".NR_CP_hits")
234 .desc("NIC requests hitting in CPU Partition")
238 .name(name
+ ".NR_NP_hits")
239 .desc("NIC requests hitting in NIC Partition")
243 .name(name
+ ".CR_CP_hits")
244 .desc("CPU requests hitting in CPU partition")
248 .name(name
+ ".CR_NP_hits")
249 .desc("CPU requests hitting in NIC partition")
254 // probe cache for presence of given block.
256 Split::probe(Addr addr
) const
258 bool success
= lru
->probe(addr
);
260 if (lifo
&& lifo_net
)
261 success
= lifo_net
->probe(addr
);
263 success
= lru_net
->probe(addr
);
270 Split::findBlock(Packet
* &pkt
, int &lat
)
273 Addr aligned
= blkAlign(pkt
->getAddr());
275 if (memHash
.count(aligned
)) {
277 } else if (pkt
->nic_pkt()) {
278 memHash
[aligned
] = 1;
281 SplitBlk
*blk
= lru
->findBlock(pkt
->getAddr(), lat
);
283 if (pkt
->nic_pkt()) {
289 if (lifo
&& lifo_net
) {
290 blk
= lifo_net
->findBlock(pkt
->getAddr(), lat
);
292 } else if (lru_net
) {
293 blk
= lru_net
->findBlock(pkt
->getAddr(), lat
);
296 if (pkt
->nic_pkt()) {
305 Tick latency
= curTick
- blk
->ts
;
307 if (!blk
->isUsed
&& !pkt
->nic_pkt()) {
308 useByCPUCycleDist
.sample(latency
);
309 nicUseByCPUCycleTotal
+= latency
;
315 if (pkt
->nic_pkt()) {
316 DPRINTF(Split
, "found block in partition %d\n", blk
->part
);
323 Split::findBlock(Addr addr
, int &lat
)
325 SplitBlk
*blk
= lru
->findBlock(addr
, lat
);
327 if (lifo
&& lifo_net
) {
328 blk
= lifo_net
->findBlock(addr
, lat
);
329 } else if (lru_net
) {
330 blk
= lru_net
->findBlock(addr
, lat
);
338 Split::findBlock(Addr addr
) const
340 SplitBlk
*blk
= lru
->findBlock(addr
);
342 if (lifo
&& lifo_net
) {
343 blk
= lifo_net
->findBlock(addr
);
344 } else if (lru_net
) {
345 blk
= lru_net
->findBlock(addr
);
353 Split::findReplacement(Packet
* &pkt
, PacketList
&writebacks
,
354 BlkList
&compress_blocks
)
358 if (pkt
->nic_pkt()) {
359 DPRINTF(Split
, "finding a replacement for nic_req\n");
361 if (lifo
&& lifo_net
)
362 blk
= lifo_net
->findReplacement(pkt
, writebacks
,
365 blk
= lru_net
->findReplacement(pkt
, writebacks
,
367 // in this case, this is an LRU only cache, it's non partitioned
369 blk
= lru
->findReplacement(pkt
, writebacks
, compress_blocks
);
371 DPRINTF(Split
, "finding replacement for cpu_req\n");
372 blk
= lru
->findReplacement(pkt
, writebacks
,
377 Tick latency
= curTick
- blk
->ts
;
380 nicUsedWhenEvicted
++;
381 usedEvictDist
.sample(latency
);
382 nicUsedTotLatency
+= latency
;
385 nicUnusedWhenEvicted
++;
386 unusedEvictDist
.sample(latency
);
387 nicUnusedTotLatency
+= latency
;
388 nicUnusedTotEvicted
++;
398 // blk attributes for the new blk coming IN
400 blk
->isNIC
= (pkt
->nic_pkt()) ? true : false;
406 Split::invalidateBlk(Addr addr
)
408 SplitBlk
*blk
= lru
->findBlock(addr
);
410 if (lifo
&& lifo_net
)
411 blk
= lifo_net
->findBlock(addr
);
413 blk
= lru_net
->findBlock(addr
);
420 blk
->isTouched
= false;
425 Split::doCopy(Addr source
, Addr dest
, PacketList
&writebacks
)
427 if (lru
->probe( source
))
428 lru
->doCopy(source
, dest
, writebacks
);
430 if (lifo
&& lifo_net
)
431 lifo_net
->doCopy(source
, dest
, writebacks
);
433 lru_net
->doCopy(source
, dest
, writebacks
);
441 if (lifo
&& lifo_net
)
442 lifo_net
->cleanupRefs();
444 lru_net
->cleanupRefs();
446 ofstream
memPrint(simout
.resolve("memory_footprint.txt").c_str(),
449 // this shouldn't be here but it happens at the end, which is what i want
450 memIter end
= memHash
.end();
451 for (memIter iter
= memHash
.begin(); iter
!= end
; ++iter
) {
452 ccprintf(memPrint
, "%8x\t%d\n", (*iter
).first
, (*iter
).second
);
457 Split::regenerateBlkAddr(Addr tag
, int set
) const
460 return lifo_net
->regenerateBlkAddr(tag
, set
);
462 return lru
->regenerateBlkAddr(tag
, set
);
466 Split::extractTag(Addr addr
, SplitBlk
*blk
) const
468 if (blk
->part
== 2) {
470 return lifo_net
->extractTag(addr
);
472 return lru_net
->extractTag(addr
);
474 panic("this shouldn't happen");
476 return lru
->extractTag(addr
);