Merge with head, hopefully the last time for this batch.
[gem5.git] / src / mem / cache / base.cc
1 /*
2 * Copyright (c) 2003-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 * Definition of BaseCache functions.
34 */
35
36 #include "cpu/base.hh"
37 #include "cpu/smt.hh"
38 #include "debug/Cache.hh"
39 #include "mem/cache/base.hh"
40 #include "mem/cache/mshr.hh"
41 #include "sim/full_system.hh"
42
43 using namespace std;
44
45 BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache,
46 const std::string &_label)
47 : SimpleTimingPort(_name, _cache), cache(_cache),
48 label(_label), blocked(false), mustSendRetry(false)
49 {
50 }
51
52
53 BaseCache::BaseCache(const Params *p)
54 : MemObject(p),
55 mshrQueue("MSHRs", p->mshrs, 4, MSHRQueue_MSHRs),
56 writeBuffer("write buffer", p->write_buffers, p->mshrs+1000,
57 MSHRQueue_WriteBuffer),
58 blkSize(p->block_size),
59 hitLatency(p->latency),
60 numTarget(p->tgts_per_mshr),
61 forwardSnoops(p->forward_snoops),
62 isTopLevel(p->is_top_level),
63 blocked(0),
64 noTargetMSHR(NULL),
65 missCount(p->max_miss_count),
66 drainEvent(NULL),
67 addrRange(p->addr_range),
68 _numCpus(p->num_cpus)
69 {
70 }
71
72
73 bool
74 BaseCache::CachePort::checkFunctional(PacketPtr pkt)
75 {
76 pkt->pushLabel(label);
77 bool done = SimpleTimingPort::checkFunctional(pkt);
78 pkt->popLabel();
79 return done;
80 }
81
82
83 unsigned
84 BaseCache::CachePort::deviceBlockSize() const
85 {
86 return cache->getBlockSize();
87 }
88
89
90 bool
91 BaseCache::CachePort::recvRetryCommon()
92 {
93 assert(waitingOnRetry);
94 waitingOnRetry = false;
95 return false;
96 }
97
98
99 void
100 BaseCache::CachePort::setBlocked()
101 {
102 assert(!blocked);
103 DPRINTF(Cache, "Cache Blocking\n");
104 blocked = true;
105 //Clear the retry flag
106 mustSendRetry = false;
107 }
108
109 void
110 BaseCache::CachePort::clearBlocked()
111 {
112 assert(blocked);
113 DPRINTF(Cache, "Cache Unblocking\n");
114 blocked = false;
115 if (mustSendRetry)
116 {
117 DPRINTF(Cache, "Cache Sending Retry\n");
118 mustSendRetry = false;
119 SendRetryEvent *ev = new SendRetryEvent(this, true);
120 // @TODO: need to find a better time (next bus cycle?)
121 cache->schedule(ev, curTick() + 1);
122 }
123 }
124
125
126 void
127 BaseCache::init()
128 {
129 if (!cpuSidePort || !memSidePort)
130 panic("Cache not hooked up on both sides\n");
131 cpuSidePort->sendRangeChange();
132 }
133
134
135 void
136 BaseCache::regStats()
137 {
138 using namespace Stats;
139
140 // Hit statistics
141 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
142 MemCmd cmd(access_idx);
143 const string &cstr = cmd.toString();
144
145 hits[access_idx]
146 .init(FullSystem ? (_numCpus + 1) : _numCpus)
147 .name(name() + "." + cstr + "_hits")
148 .desc("number of " + cstr + " hits")
149 .flags(total | nozero | nonan)
150 ;
151 }
152
153 // These macros make it easier to sum the right subset of commands and
154 // to change the subset of commands that are considered "demand" vs
155 // "non-demand"
156 #define SUM_DEMAND(s) \
157 (s[MemCmd::ReadReq] + s[MemCmd::WriteReq] + s[MemCmd::ReadExReq])
158
159 // should writebacks be included here? prior code was inconsistent...
160 #define SUM_NON_DEMAND(s) \
161 (s[MemCmd::SoftPFReq] + s[MemCmd::HardPFReq])
162
163 demandHits
164 .name(name() + ".demand_hits")
165 .desc("number of demand (read+write) hits")
166 .flags(total)
167 ;
168 demandHits = SUM_DEMAND(hits);
169
170 overallHits
171 .name(name() + ".overall_hits")
172 .desc("number of overall hits")
173 .flags(total)
174 ;
175 overallHits = demandHits + SUM_NON_DEMAND(hits);
176
177 // Miss statistics
178 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
179 MemCmd cmd(access_idx);
180 const string &cstr = cmd.toString();
181
182 misses[access_idx]
183 .init(FullSystem ? (_numCpus + 1) : _numCpus)
184 .name(name() + "." + cstr + "_misses")
185 .desc("number of " + cstr + " misses")
186 .flags(total | nozero | nonan)
187 ;
188 }
189
190 demandMisses
191 .name(name() + ".demand_misses")
192 .desc("number of demand (read+write) misses")
193 .flags(total)
194 ;
195 demandMisses = SUM_DEMAND(misses);
196
197 overallMisses
198 .name(name() + ".overall_misses")
199 .desc("number of overall misses")
200 .flags(total)
201 ;
202 overallMisses = demandMisses + SUM_NON_DEMAND(misses);
203
204 // Miss latency statistics
205 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
206 MemCmd cmd(access_idx);
207 const string &cstr = cmd.toString();
208
209 missLatency[access_idx]
210 .init(maxThreadsPerCPU)
211 .name(name() + "." + cstr + "_miss_latency")
212 .desc("number of " + cstr + " miss cycles")
213 .flags(total | nozero | nonan)
214 ;
215 }
216
217 demandMissLatency
218 .name(name() + ".demand_miss_latency")
219 .desc("number of demand (read+write) miss cycles")
220 .flags(total)
221 ;
222 demandMissLatency = SUM_DEMAND(missLatency);
223
224 overallMissLatency
225 .name(name() + ".overall_miss_latency")
226 .desc("number of overall miss cycles")
227 .flags(total)
228 ;
229 overallMissLatency = demandMissLatency + SUM_NON_DEMAND(missLatency);
230
231 // access formulas
232 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
233 MemCmd cmd(access_idx);
234 const string &cstr = cmd.toString();
235
236 accesses[access_idx]
237 .name(name() + "." + cstr + "_accesses")
238 .desc("number of " + cstr + " accesses(hits+misses)")
239 .flags(total | nozero | nonan)
240 ;
241
242 accesses[access_idx] = hits[access_idx] + misses[access_idx];
243 }
244
245 demandAccesses
246 .name(name() + ".demand_accesses")
247 .desc("number of demand (read+write) accesses")
248 .flags(total)
249 ;
250 demandAccesses = demandHits + demandMisses;
251
252 overallAccesses
253 .name(name() + ".overall_accesses")
254 .desc("number of overall (read+write) accesses")
255 .flags(total)
256 ;
257 overallAccesses = overallHits + overallMisses;
258
259 // miss rate formulas
260 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
261 MemCmd cmd(access_idx);
262 const string &cstr = cmd.toString();
263
264 missRate[access_idx]
265 .name(name() + "." + cstr + "_miss_rate")
266 .desc("miss rate for " + cstr + " accesses")
267 .flags(total | nozero | nonan)
268 ;
269
270 missRate[access_idx] = misses[access_idx] / accesses[access_idx];
271 }
272
273 demandMissRate
274 .name(name() + ".demand_miss_rate")
275 .desc("miss rate for demand accesses")
276 .flags(total)
277 ;
278 demandMissRate = demandMisses / demandAccesses;
279
280 overallMissRate
281 .name(name() + ".overall_miss_rate")
282 .desc("miss rate for overall accesses")
283 .flags(total)
284 ;
285 overallMissRate = overallMisses / overallAccesses;
286
287 // miss latency formulas
288 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
289 MemCmd cmd(access_idx);
290 const string &cstr = cmd.toString();
291
292 avgMissLatency[access_idx]
293 .name(name() + "." + cstr + "_avg_miss_latency")
294 .desc("average " + cstr + " miss latency")
295 .flags(total | nozero | nonan)
296 ;
297
298 avgMissLatency[access_idx] =
299 missLatency[access_idx] / misses[access_idx];
300 }
301
302 demandAvgMissLatency
303 .name(name() + ".demand_avg_miss_latency")
304 .desc("average overall miss latency")
305 .flags(total)
306 ;
307 demandAvgMissLatency = demandMissLatency / demandMisses;
308
309 overallAvgMissLatency
310 .name(name() + ".overall_avg_miss_latency")
311 .desc("average overall miss latency")
312 .flags(total)
313 ;
314 overallAvgMissLatency = overallMissLatency / overallMisses;
315
316 blocked_cycles.init(NUM_BLOCKED_CAUSES);
317 blocked_cycles
318 .name(name() + ".blocked_cycles")
319 .desc("number of cycles access was blocked")
320 .subname(Blocked_NoMSHRs, "no_mshrs")
321 .subname(Blocked_NoTargets, "no_targets")
322 ;
323
324
325 blocked_causes.init(NUM_BLOCKED_CAUSES);
326 blocked_causes
327 .name(name() + ".blocked")
328 .desc("number of cycles access was blocked")
329 .subname(Blocked_NoMSHRs, "no_mshrs")
330 .subname(Blocked_NoTargets, "no_targets")
331 ;
332
333 avg_blocked
334 .name(name() + ".avg_blocked_cycles")
335 .desc("average number of cycles each access was blocked")
336 .subname(Blocked_NoMSHRs, "no_mshrs")
337 .subname(Blocked_NoTargets, "no_targets")
338 ;
339
340 avg_blocked = blocked_cycles / blocked_causes;
341
342 fastWrites
343 .name(name() + ".fast_writes")
344 .desc("number of fast writes performed")
345 ;
346
347 cacheCopies
348 .name(name() + ".cache_copies")
349 .desc("number of cache copies performed")
350 ;
351
352 writebacks
353 .init(maxThreadsPerCPU)
354 .name(name() + ".writebacks")
355 .desc("number of writebacks")
356 .flags(total)
357 ;
358
359 // MSHR statistics
360 // MSHR hit statistics
361 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
362 MemCmd cmd(access_idx);
363 const string &cstr = cmd.toString();
364
365 mshr_hits[access_idx]
366 .init(maxThreadsPerCPU)
367 .name(name() + "." + cstr + "_mshr_hits")
368 .desc("number of " + cstr + " MSHR hits")
369 .flags(total | nozero | nonan)
370 ;
371 }
372
373 demandMshrHits
374 .name(name() + ".demand_mshr_hits")
375 .desc("number of demand (read+write) MSHR hits")
376 .flags(total)
377 ;
378 demandMshrHits = SUM_DEMAND(mshr_hits);
379
380 overallMshrHits
381 .name(name() + ".overall_mshr_hits")
382 .desc("number of overall MSHR hits")
383 .flags(total)
384 ;
385 overallMshrHits = demandMshrHits + SUM_NON_DEMAND(mshr_hits);
386
387 // MSHR miss statistics
388 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
389 MemCmd cmd(access_idx);
390 const string &cstr = cmd.toString();
391
392 mshr_misses[access_idx]
393 .init(maxThreadsPerCPU)
394 .name(name() + "." + cstr + "_mshr_misses")
395 .desc("number of " + cstr + " MSHR misses")
396 .flags(total | nozero | nonan)
397 ;
398 }
399
400 demandMshrMisses
401 .name(name() + ".demand_mshr_misses")
402 .desc("number of demand (read+write) MSHR misses")
403 .flags(total)
404 ;
405 demandMshrMisses = SUM_DEMAND(mshr_misses);
406
407 overallMshrMisses
408 .name(name() + ".overall_mshr_misses")
409 .desc("number of overall MSHR misses")
410 .flags(total)
411 ;
412 overallMshrMisses = demandMshrMisses + SUM_NON_DEMAND(mshr_misses);
413
414 // MSHR miss latency statistics
415 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
416 MemCmd cmd(access_idx);
417 const string &cstr = cmd.toString();
418
419 mshr_miss_latency[access_idx]
420 .init(maxThreadsPerCPU)
421 .name(name() + "." + cstr + "_mshr_miss_latency")
422 .desc("number of " + cstr + " MSHR miss cycles")
423 .flags(total | nozero | nonan)
424 ;
425 }
426
427 demandMshrMissLatency
428 .name(name() + ".demand_mshr_miss_latency")
429 .desc("number of demand (read+write) MSHR miss cycles")
430 .flags(total)
431 ;
432 demandMshrMissLatency = SUM_DEMAND(mshr_miss_latency);
433
434 overallMshrMissLatency
435 .name(name() + ".overall_mshr_miss_latency")
436 .desc("number of overall MSHR miss cycles")
437 .flags(total)
438 ;
439 overallMshrMissLatency =
440 demandMshrMissLatency + SUM_NON_DEMAND(mshr_miss_latency);
441
442 // MSHR uncacheable statistics
443 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
444 MemCmd cmd(access_idx);
445 const string &cstr = cmd.toString();
446
447 mshr_uncacheable[access_idx]
448 .init(maxThreadsPerCPU)
449 .name(name() + "." + cstr + "_mshr_uncacheable")
450 .desc("number of " + cstr + " MSHR uncacheable")
451 .flags(total | nozero | nonan)
452 ;
453 }
454
455 overallMshrUncacheable
456 .name(name() + ".overall_mshr_uncacheable_misses")
457 .desc("number of overall MSHR uncacheable misses")
458 .flags(total)
459 ;
460 overallMshrUncacheable =
461 SUM_DEMAND(mshr_uncacheable) + SUM_NON_DEMAND(mshr_uncacheable);
462
463 // MSHR miss latency statistics
464 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
465 MemCmd cmd(access_idx);
466 const string &cstr = cmd.toString();
467
468 mshr_uncacheable_lat[access_idx]
469 .init(maxThreadsPerCPU)
470 .name(name() + "." + cstr + "_mshr_uncacheable_latency")
471 .desc("number of " + cstr + " MSHR uncacheable cycles")
472 .flags(total | nozero | nonan)
473 ;
474 }
475
476 overallMshrUncacheableLatency
477 .name(name() + ".overall_mshr_uncacheable_latency")
478 .desc("number of overall MSHR uncacheable cycles")
479 .flags(total)
480 ;
481 overallMshrUncacheableLatency =
482 SUM_DEMAND(mshr_uncacheable_lat) +
483 SUM_NON_DEMAND(mshr_uncacheable_lat);
484
485 #if 0
486 // MSHR access formulas
487 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
488 MemCmd cmd(access_idx);
489 const string &cstr = cmd.toString();
490
491 mshrAccesses[access_idx]
492 .name(name() + "." + cstr + "_mshr_accesses")
493 .desc("number of " + cstr + " mshr accesses(hits+misses)")
494 .flags(total | nozero | nonan)
495 ;
496 mshrAccesses[access_idx] =
497 mshr_hits[access_idx] + mshr_misses[access_idx]
498 + mshr_uncacheable[access_idx];
499 }
500
501 demandMshrAccesses
502 .name(name() + ".demand_mshr_accesses")
503 .desc("number of demand (read+write) mshr accesses")
504 .flags(total | nozero | nonan)
505 ;
506 demandMshrAccesses = demandMshrHits + demandMshrMisses;
507
508 overallMshrAccesses
509 .name(name() + ".overall_mshr_accesses")
510 .desc("number of overall (read+write) mshr accesses")
511 .flags(total | nozero | nonan)
512 ;
513 overallMshrAccesses = overallMshrHits + overallMshrMisses
514 + overallMshrUncacheable;
515 #endif
516
517 // MSHR miss rate formulas
518 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
519 MemCmd cmd(access_idx);
520 const string &cstr = cmd.toString();
521
522 mshrMissRate[access_idx]
523 .name(name() + "." + cstr + "_mshr_miss_rate")
524 .desc("mshr miss rate for " + cstr + " accesses")
525 .flags(total | nozero | nonan)
526 ;
527
528 mshrMissRate[access_idx] =
529 mshr_misses[access_idx] / accesses[access_idx];
530 }
531
532 demandMshrMissRate
533 .name(name() + ".demand_mshr_miss_rate")
534 .desc("mshr miss rate for demand accesses")
535 .flags(total)
536 ;
537 demandMshrMissRate = demandMshrMisses / demandAccesses;
538
539 overallMshrMissRate
540 .name(name() + ".overall_mshr_miss_rate")
541 .desc("mshr miss rate for overall accesses")
542 .flags(total)
543 ;
544 overallMshrMissRate = overallMshrMisses / overallAccesses;
545
546 // mshrMiss latency formulas
547 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
548 MemCmd cmd(access_idx);
549 const string &cstr = cmd.toString();
550
551 avgMshrMissLatency[access_idx]
552 .name(name() + "." + cstr + "_avg_mshr_miss_latency")
553 .desc("average " + cstr + " mshr miss latency")
554 .flags(total | nozero | nonan)
555 ;
556
557 avgMshrMissLatency[access_idx] =
558 mshr_miss_latency[access_idx] / mshr_misses[access_idx];
559 }
560
561 demandAvgMshrMissLatency
562 .name(name() + ".demand_avg_mshr_miss_latency")
563 .desc("average overall mshr miss latency")
564 .flags(total)
565 ;
566 demandAvgMshrMissLatency = demandMshrMissLatency / demandMshrMisses;
567
568 overallAvgMshrMissLatency
569 .name(name() + ".overall_avg_mshr_miss_latency")
570 .desc("average overall mshr miss latency")
571 .flags(total)
572 ;
573 overallAvgMshrMissLatency = overallMshrMissLatency / overallMshrMisses;
574
575 // mshrUncacheable latency formulas
576 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
577 MemCmd cmd(access_idx);
578 const string &cstr = cmd.toString();
579
580 avgMshrUncacheableLatency[access_idx]
581 .name(name() + "." + cstr + "_avg_mshr_uncacheable_latency")
582 .desc("average " + cstr + " mshr uncacheable latency")
583 .flags(total | nozero | nonan)
584 ;
585
586 avgMshrUncacheableLatency[access_idx] =
587 mshr_uncacheable_lat[access_idx] / mshr_uncacheable[access_idx];
588 }
589
590 overallAvgMshrUncacheableLatency
591 .name(name() + ".overall_avg_mshr_uncacheable_latency")
592 .desc("average overall mshr uncacheable latency")
593 .flags(total)
594 ;
595 overallAvgMshrUncacheableLatency = overallMshrUncacheableLatency / overallMshrUncacheable;
596
597 mshr_cap_events
598 .init(maxThreadsPerCPU)
599 .name(name() + ".mshr_cap_events")
600 .desc("number of times MSHR cap was activated")
601 .flags(total)
602 ;
603
604 //software prefetching stats
605 soft_prefetch_mshr_full
606 .init(maxThreadsPerCPU)
607 .name(name() + ".soft_prefetch_mshr_full")
608 .desc("number of mshr full events for SW prefetching instrutions")
609 .flags(total)
610 ;
611
612 mshr_no_allocate_misses
613 .name(name() +".no_allocate_misses")
614 .desc("Number of misses that were no-allocate")
615 ;
616
617 }
618
619 unsigned int
620 BaseCache::drain(Event *de)
621 {
622 int count = memSidePort->drain(de) + cpuSidePort->drain(de);
623
624 // Set status
625 if (count != 0) {
626 drainEvent = de;
627
628 changeState(SimObject::Draining);
629 return count;
630 }
631
632 changeState(SimObject::Drained);
633 return 0;
634 }