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