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