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