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