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