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