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