base.cc revision 4666
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->result != Packet::Success)
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    demandHits
154        .name(name() + ".demand_hits")
155        .desc("number of demand (read+write) hits")
156        .flags(total)
157        ;
158    demandHits = hits[MemCmd::ReadReq] + hits[MemCmd::WriteReq];
159
160    overallHits
161        .name(name() + ".overall_hits")
162        .desc("number of overall hits")
163        .flags(total)
164        ;
165    overallHits = demandHits + hits[MemCmd::SoftPFReq] + hits[MemCmd::HardPFReq]
166        + hits[MemCmd::Writeback];
167
168    // Miss statistics
169    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
170        MemCmd cmd(access_idx);
171        const string &cstr = cmd.toString();
172
173        misses[access_idx]
174            .init(maxThreadsPerCPU)
175            .name(name() + "." + cstr + "_misses")
176            .desc("number of " + cstr + " misses")
177            .flags(total | nozero | nonan)
178            ;
179    }
180
181    demandMisses
182        .name(name() + ".demand_misses")
183        .desc("number of demand (read+write) misses")
184        .flags(total)
185        ;
186    demandMisses = misses[MemCmd::ReadReq] + misses[MemCmd::WriteReq];
187
188    overallMisses
189        .name(name() + ".overall_misses")
190        .desc("number of overall misses")
191        .flags(total)
192        ;
193    overallMisses = demandMisses + misses[MemCmd::SoftPFReq] +
194        misses[MemCmd::HardPFReq] + misses[MemCmd::Writeback];
195
196    // Miss latency statistics
197    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
198        MemCmd cmd(access_idx);
199        const string &cstr = cmd.toString();
200
201        missLatency[access_idx]
202            .init(maxThreadsPerCPU)
203            .name(name() + "." + cstr + "_miss_latency")
204            .desc("number of " + cstr + " miss cycles")
205            .flags(total | nozero | nonan)
206            ;
207    }
208
209    demandMissLatency
210        .name(name() + ".demand_miss_latency")
211        .desc("number of demand (read+write) miss cycles")
212        .flags(total)
213        ;
214    demandMissLatency = missLatency[MemCmd::ReadReq] + missLatency[MemCmd::WriteReq];
215
216    overallMissLatency
217        .name(name() + ".overall_miss_latency")
218        .desc("number of overall miss cycles")
219        .flags(total)
220        ;
221    overallMissLatency = demandMissLatency + missLatency[MemCmd::SoftPFReq] +
222        missLatency[MemCmd::HardPFReq];
223
224    // access formulas
225    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
226        MemCmd cmd(access_idx);
227        const string &cstr = cmd.toString();
228
229        accesses[access_idx]
230            .name(name() + "." + cstr + "_accesses")
231            .desc("number of " + cstr + " accesses(hits+misses)")
232            .flags(total | nozero | nonan)
233            ;
234
235        accesses[access_idx] = hits[access_idx] + misses[access_idx];
236    }
237
238    demandAccesses
239        .name(name() + ".demand_accesses")
240        .desc("number of demand (read+write) accesses")
241        .flags(total)
242        ;
243    demandAccesses = demandHits + demandMisses;
244
245    overallAccesses
246        .name(name() + ".overall_accesses")
247        .desc("number of overall (read+write) accesses")
248        .flags(total)
249        ;
250    overallAccesses = overallHits + overallMisses;
251
252    // miss rate formulas
253    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
254        MemCmd cmd(access_idx);
255        const string &cstr = cmd.toString();
256
257        missRate[access_idx]
258            .name(name() + "." + cstr + "_miss_rate")
259            .desc("miss rate for " + cstr + " accesses")
260            .flags(total | nozero | nonan)
261            ;
262
263        missRate[access_idx] = misses[access_idx] / accesses[access_idx];
264    }
265
266    demandMissRate
267        .name(name() + ".demand_miss_rate")
268        .desc("miss rate for demand accesses")
269        .flags(total)
270        ;
271    demandMissRate = demandMisses / demandAccesses;
272
273    overallMissRate
274        .name(name() + ".overall_miss_rate")
275        .desc("miss rate for overall accesses")
276        .flags(total)
277        ;
278    overallMissRate = overallMisses / overallAccesses;
279
280    // miss latency formulas
281    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
282        MemCmd cmd(access_idx);
283        const string &cstr = cmd.toString();
284
285        avgMissLatency[access_idx]
286            .name(name() + "." + cstr + "_avg_miss_latency")
287            .desc("average " + cstr + " miss latency")
288            .flags(total | nozero | nonan)
289            ;
290
291        avgMissLatency[access_idx] =
292            missLatency[access_idx] / misses[access_idx];
293    }
294
295    demandAvgMissLatency
296        .name(name() + ".demand_avg_miss_latency")
297        .desc("average overall miss latency")
298        .flags(total)
299        ;
300    demandAvgMissLatency = demandMissLatency / demandMisses;
301
302    overallAvgMissLatency
303        .name(name() + ".overall_avg_miss_latency")
304        .desc("average overall miss latency")
305        .flags(total)
306        ;
307    overallAvgMissLatency = overallMissLatency / overallMisses;
308
309    blocked_cycles.init(NUM_BLOCKED_CAUSES);
310    blocked_cycles
311        .name(name() + ".blocked_cycles")
312        .desc("number of cycles access was blocked")
313        .subname(Blocked_NoMSHRs, "no_mshrs")
314        .subname(Blocked_NoTargets, "no_targets")
315        ;
316
317
318    blocked_causes.init(NUM_BLOCKED_CAUSES);
319    blocked_causes
320        .name(name() + ".blocked")
321        .desc("number of cycles access was blocked")
322        .subname(Blocked_NoMSHRs, "no_mshrs")
323        .subname(Blocked_NoTargets, "no_targets")
324        ;
325
326    avg_blocked
327        .name(name() + ".avg_blocked_cycles")
328        .desc("average number of cycles each access was blocked")
329        .subname(Blocked_NoMSHRs, "no_mshrs")
330        .subname(Blocked_NoTargets, "no_targets")
331        ;
332
333    avg_blocked = blocked_cycles / blocked_causes;
334
335    fastWrites
336        .name(name() + ".fast_writes")
337        .desc("number of fast writes performed")
338        ;
339
340    cacheCopies
341        .name(name() + ".cache_copies")
342        .desc("number of cache copies performed")
343        ;
344
345    writebacks
346        .init(maxThreadsPerCPU)
347        .name(name() + ".writebacks")
348        .desc("number of writebacks")
349        .flags(total)
350        ;
351
352    // MSHR statistics
353    // MSHR hit statistics
354    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
355        MemCmd cmd(access_idx);
356        const string &cstr = cmd.toString();
357
358        mshr_hits[access_idx]
359            .init(maxThreadsPerCPU)
360            .name(name() + "." + cstr + "_mshr_hits")
361            .desc("number of " + cstr + " MSHR hits")
362            .flags(total | nozero | nonan)
363            ;
364    }
365
366    demandMshrHits
367        .name(name() + ".demand_mshr_hits")
368        .desc("number of demand (read+write) MSHR hits")
369        .flags(total)
370        ;
371    demandMshrHits = mshr_hits[MemCmd::ReadReq] + mshr_hits[MemCmd::WriteReq];
372
373    overallMshrHits
374        .name(name() + ".overall_mshr_hits")
375        .desc("number of overall MSHR hits")
376        .flags(total)
377        ;
378    overallMshrHits = demandMshrHits + mshr_hits[MemCmd::SoftPFReq] +
379        mshr_hits[MemCmd::HardPFReq];
380
381    // MSHR miss statistics
382    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
383        MemCmd cmd(access_idx);
384        const string &cstr = cmd.toString();
385
386        mshr_misses[access_idx]
387            .init(maxThreadsPerCPU)
388            .name(name() + "." + cstr + "_mshr_misses")
389            .desc("number of " + cstr + " MSHR misses")
390            .flags(total | nozero | nonan)
391            ;
392    }
393
394    demandMshrMisses
395        .name(name() + ".demand_mshr_misses")
396        .desc("number of demand (read+write) MSHR misses")
397        .flags(total)
398        ;
399    demandMshrMisses = mshr_misses[MemCmd::ReadReq] + mshr_misses[MemCmd::WriteReq];
400
401    overallMshrMisses
402        .name(name() + ".overall_mshr_misses")
403        .desc("number of overall MSHR misses")
404        .flags(total)
405        ;
406    overallMshrMisses = demandMshrMisses + mshr_misses[MemCmd::SoftPFReq] +
407        mshr_misses[MemCmd::HardPFReq];
408
409    // MSHR miss latency statistics
410    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
411        MemCmd cmd(access_idx);
412        const string &cstr = cmd.toString();
413
414        mshr_miss_latency[access_idx]
415            .init(maxThreadsPerCPU)
416            .name(name() + "." + cstr + "_mshr_miss_latency")
417            .desc("number of " + cstr + " MSHR miss cycles")
418            .flags(total | nozero | nonan)
419            ;
420    }
421
422    demandMshrMissLatency
423        .name(name() + ".demand_mshr_miss_latency")
424        .desc("number of demand (read+write) MSHR miss cycles")
425        .flags(total)
426        ;
427    demandMshrMissLatency = mshr_miss_latency[MemCmd::ReadReq]
428        + mshr_miss_latency[MemCmd::WriteReq];
429
430    overallMshrMissLatency
431        .name(name() + ".overall_mshr_miss_latency")
432        .desc("number of overall MSHR miss cycles")
433        .flags(total)
434        ;
435    overallMshrMissLatency = demandMshrMissLatency +
436        mshr_miss_latency[MemCmd::SoftPFReq] + mshr_miss_latency[MemCmd::HardPFReq];
437
438    // MSHR uncacheable statistics
439    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
440        MemCmd cmd(access_idx);
441        const string &cstr = cmd.toString();
442
443        mshr_uncacheable[access_idx]
444            .init(maxThreadsPerCPU)
445            .name(name() + "." + cstr + "_mshr_uncacheable")
446            .desc("number of " + cstr + " MSHR uncacheable")
447            .flags(total | nozero | nonan)
448            ;
449    }
450
451    overallMshrUncacheable
452        .name(name() + ".overall_mshr_uncacheable_misses")
453        .desc("number of overall MSHR uncacheable misses")
454        .flags(total)
455        ;
456    overallMshrUncacheable = mshr_uncacheable[MemCmd::ReadReq]
457        + mshr_uncacheable[MemCmd::WriteReq] + mshr_uncacheable[MemCmd::SoftPFReq]
458        + mshr_uncacheable[MemCmd::HardPFReq];
459
460    // MSHR miss latency statistics
461    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
462        MemCmd cmd(access_idx);
463        const string &cstr = cmd.toString();
464
465        mshr_uncacheable_lat[access_idx]
466            .init(maxThreadsPerCPU)
467            .name(name() + "." + cstr + "_mshr_uncacheable_latency")
468            .desc("number of " + cstr + " MSHR uncacheable cycles")
469            .flags(total | nozero | nonan)
470            ;
471    }
472
473    overallMshrUncacheableLatency
474        .name(name() + ".overall_mshr_uncacheable_latency")
475        .desc("number of overall MSHR uncacheable cycles")
476        .flags(total)
477        ;
478    overallMshrUncacheableLatency = mshr_uncacheable_lat[MemCmd::ReadReq]
479        + mshr_uncacheable_lat[MemCmd::WriteReq]
480        + mshr_uncacheable_lat[MemCmd::SoftPFReq]
481        + mshr_uncacheable_lat[MemCmd::HardPFReq];
482
483#if 0
484    // MSHR access formulas
485    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
486        MemCmd cmd(access_idx);
487        const string &cstr = cmd.toString();
488
489        mshrAccesses[access_idx]
490            .name(name() + "." + cstr + "_mshr_accesses")
491            .desc("number of " + cstr + " mshr accesses(hits+misses)")
492            .flags(total | nozero | nonan)
493            ;
494        mshrAccesses[access_idx] =
495            mshr_hits[access_idx] + mshr_misses[access_idx]
496            + mshr_uncacheable[access_idx];
497    }
498
499    demandMshrAccesses
500        .name(name() + ".demand_mshr_accesses")
501        .desc("number of demand (read+write) mshr accesses")
502        .flags(total | nozero | nonan)
503        ;
504    demandMshrAccesses = demandMshrHits + demandMshrMisses;
505
506    overallMshrAccesses
507        .name(name() + ".overall_mshr_accesses")
508        .desc("number of overall (read+write) mshr accesses")
509        .flags(total | nozero | nonan)
510        ;
511    overallMshrAccesses = overallMshrHits + overallMshrMisses
512        + overallMshrUncacheable;
513#endif
514
515    // MSHR miss rate formulas
516    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
517        MemCmd cmd(access_idx);
518        const string &cstr = cmd.toString();
519
520        mshrMissRate[access_idx]
521            .name(name() + "." + cstr + "_mshr_miss_rate")
522            .desc("mshr miss rate for " + cstr + " accesses")
523            .flags(total | nozero | nonan)
524            ;
525
526        mshrMissRate[access_idx] =
527            mshr_misses[access_idx] / accesses[access_idx];
528    }
529
530    demandMshrMissRate
531        .name(name() + ".demand_mshr_miss_rate")
532        .desc("mshr miss rate for demand accesses")
533        .flags(total)
534        ;
535    demandMshrMissRate = demandMshrMisses / demandAccesses;
536
537    overallMshrMissRate
538        .name(name() + ".overall_mshr_miss_rate")
539        .desc("mshr miss rate for overall accesses")
540        .flags(total)
541        ;
542    overallMshrMissRate = overallMshrMisses / overallAccesses;
543
544    // mshrMiss latency formulas
545    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
546        MemCmd cmd(access_idx);
547        const string &cstr = cmd.toString();
548
549        avgMshrMissLatency[access_idx]
550            .name(name() + "." + cstr + "_avg_mshr_miss_latency")
551            .desc("average " + cstr + " mshr miss latency")
552            .flags(total | nozero | nonan)
553            ;
554
555        avgMshrMissLatency[access_idx] =
556            mshr_miss_latency[access_idx] / mshr_misses[access_idx];
557    }
558
559    demandAvgMshrMissLatency
560        .name(name() + ".demand_avg_mshr_miss_latency")
561        .desc("average overall mshr miss latency")
562        .flags(total)
563        ;
564    demandAvgMshrMissLatency = demandMshrMissLatency / demandMshrMisses;
565
566    overallAvgMshrMissLatency
567        .name(name() + ".overall_avg_mshr_miss_latency")
568        .desc("average overall mshr miss latency")
569        .flags(total)
570        ;
571    overallAvgMshrMissLatency = overallMshrMissLatency / overallMshrMisses;
572
573    // mshrUncacheable latency formulas
574    for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) {
575        MemCmd cmd(access_idx);
576        const string &cstr = cmd.toString();
577
578        avgMshrUncacheableLatency[access_idx]
579            .name(name() + "." + cstr + "_avg_mshr_uncacheable_latency")
580            .desc("average " + cstr + " mshr uncacheable latency")
581            .flags(total | nozero | nonan)
582            ;
583
584        avgMshrUncacheableLatency[access_idx] =
585            mshr_uncacheable_lat[access_idx] / mshr_uncacheable[access_idx];
586    }
587
588    overallAvgMshrUncacheableLatency
589        .name(name() + ".overall_avg_mshr_uncacheable_latency")
590        .desc("average overall mshr uncacheable latency")
591        .flags(total)
592        ;
593    overallAvgMshrUncacheableLatency = overallMshrUncacheableLatency / overallMshrUncacheable;
594
595    mshr_cap_events
596        .init(maxThreadsPerCPU)
597        .name(name() + ".mshr_cap_events")
598        .desc("number of times MSHR cap was activated")
599        .flags(total)
600        ;
601
602    //software prefetching stats
603    soft_prefetch_mshr_full
604        .init(maxThreadsPerCPU)
605        .name(name() + ".soft_prefetch_mshr_full")
606        .desc("number of mshr full events for SW prefetching instrutions")
607        .flags(total)
608        ;
609
610    mshr_no_allocate_misses
611        .name(name() +".no_allocate_misses")
612        .desc("Number of misses that were no-allocate")
613        ;
614
615}
616
617unsigned int
618BaseCache::drain(Event *de)
619{
620    int count = memSidePort->drain(de) + cpuSidePort->drain(de);
621
622    // Set status
623    if (count != 0) {
624        drainEvent = de;
625
626        changeState(SimObject::Draining);
627        return count;
628    }
629
630    changeState(SimObject::Drained);
631    return 0;
632}
633