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