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