base.cc revision 3013
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 "mem/cache/base_cache.hh"
37#include "cpu/smt.hh"
38#include "cpu/base.hh"
39
40using namespace std;
41
42BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache,
43                                bool _isCpuSide)
44    : Port(_name), cache(_cache), isCpuSide(_isCpuSide)
45{
46    blocked = false;
47    //Start ports at null if more than one is created we should panic
48    //cpuSidePort = NULL;
49    //memSidePort = NULL;
50}
51
52void
53BaseCache::CachePort::recvStatusChange(Port::Status status)
54{
55    cache->recvStatusChange(status, isCpuSide);
56}
57
58void
59BaseCache::CachePort::getDeviceAddressRanges(AddrRangeList &resp,
60                                       AddrRangeList &snoop)
61{
62    cache->getAddressRanges(resp, snoop, isCpuSide);
63}
64
65int
66BaseCache::CachePort::deviceBlockSize()
67{
68    return cache->getBlockSize();
69}
70
71bool
72BaseCache::CachePort::recvTiming(Packet *pkt)
73{
74    if (blocked)
75    {
76        DPRINTF(Cache,"Scheduling a retry while blocked\n");
77        mustSendRetry = true;
78        return false;
79    }
80    return cache->doTimingAccess(pkt, this, isCpuSide);
81}
82
83Tick
84BaseCache::CachePort::recvAtomic(Packet *pkt)
85{
86    return cache->doAtomicAccess(pkt, isCpuSide);
87}
88
89void
90BaseCache::CachePort::recvFunctional(Packet *pkt)
91{
92    cache->doFunctionalAccess(pkt, isCpuSide);
93}
94
95void
96BaseCache::CachePort::recvRetry()
97{
98    Packet *pkt;
99
100    if (!isCpuSide)
101    {
102        pkt = cache->getPacket();
103        bool success = sendTiming(pkt);
104        DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
105                pkt->getAddr(), success ? "succesful" : "unsuccesful");
106        cache->sendResult(pkt, success);
107        if (success && cache->doMasterRequest())
108        {
109            //Still more to issue, rerequest in 1 cycle
110            pkt = NULL;
111            BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(this);
112            reqCpu->schedule(curTick + 1);
113        }
114    }
115    else
116    {
117        pkt = cache->getCoherencePacket();
118        bool success = sendTiming(pkt);
119        if (success && cache->doSlaveRequest())
120        {
121            //Still more to issue, rerequest in 1 cycle
122            pkt = NULL;
123            BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(this);
124            reqCpu->schedule(curTick + 1);
125        }
126
127    }
128    return;
129}
130void
131BaseCache::CachePort::setBlocked()
132{
133    assert(!blocked);
134    DPRINTF(Cache, "Cache Blocking\n");
135    blocked = true;
136    //Clear the retry flag
137    mustSendRetry = false;
138}
139
140void
141BaseCache::CachePort::clearBlocked()
142{
143    assert(blocked);
144    DPRINTF(Cache, "Cache Unblocking\n");
145    blocked = false;
146    if (mustSendRetry)
147    {
148        DPRINTF(Cache, "Cache Sending Retry\n");
149        mustSendRetry = false;
150        sendRetry();
151    }
152}
153
154BaseCache::CacheEvent::CacheEvent(CachePort *_cachePort)
155    : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort)
156{
157    this->setFlags(AutoDelete);
158    pkt = NULL;
159}
160
161BaseCache::CacheEvent::CacheEvent(CachePort *_cachePort, Packet *_pkt)
162    : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort), pkt(_pkt)
163{
164    this->setFlags(AutoDelete);
165}
166
167void
168BaseCache::CacheEvent::process()
169{
170    if (!pkt)
171    {
172        if (!cachePort->isCpuSide)
173        {
174            //MSHR
175            pkt = cachePort->cache->getPacket();
176            bool success = cachePort->sendTiming(pkt);
177            DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
178                    pkt->getAddr(), success ? "succesful" : "unsuccesful");
179            cachePort->cache->sendResult(pkt, success);
180            if (success && cachePort->cache->doMasterRequest())
181            {
182                //Still more to issue, rerequest in 1 cycle
183                pkt = NULL;
184                this->schedule(curTick+1);
185            }
186        }
187        else
188        {
189            //CSHR
190            pkt = cachePort->cache->getCoherencePacket();
191            bool success = cachePort->sendTiming(pkt);
192            if (success && cachePort->cache->doSlaveRequest())
193            {
194                //Still more to issue, rerequest in 1 cycle
195                pkt = NULL;
196                this->schedule(curTick+1);
197            }
198        }
199        return;
200    }
201    //Response
202    //Know the packet to send, no need to mark in service (must succed)
203    bool success = cachePort->sendTiming(pkt);
204    assert(success);
205}
206
207const char *
208BaseCache::CacheEvent::description()
209{
210    return "timing event\n";
211}
212
213Port*
214BaseCache::getPort(const std::string &if_name, int idx)
215{
216    if (if_name == "")
217    {
218        if(cpuSidePort == NULL)
219            cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
220        return cpuSidePort;
221    }
222    else if (if_name == "functional")
223    {
224        if(cpuSidePort == NULL)
225            cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
226        return cpuSidePort;
227    }
228    else if (if_name == "cpu_side")
229    {
230        if(cpuSidePort == NULL)
231            cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
232        return cpuSidePort;
233    }
234    else if (if_name == "mem_side")
235    {
236        if (memSidePort != NULL)
237            panic("Already have a mem side for this cache\n");
238        memSidePort = new CachePort(name() + "-mem_side_port", this, false);
239        return memSidePort;
240    }
241    else panic("Port name %s unrecognized\n", if_name);
242}
243
244void
245BaseCache::init()
246{
247    if (!cpuSidePort || !memSidePort)
248        panic("Cache not hooked up on both sides\n");
249    cpuSidePort->sendStatusChange(Port::RangeChange);
250}
251
252void
253BaseCache::regStats()
254{
255    Request temp_req((Addr) NULL, 4, 0);
256    Packet::Command temp_cmd = Packet::ReadReq;
257    Packet temp_pkt(&temp_req, temp_cmd, 0);  //@todo FIx command strings so this isn't neccessary
258    temp_pkt.allocate(); //Temp allocate, all need data
259
260    using namespace Stats;
261
262    // Hit statistics
263    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
264        Packet::Command cmd = (Packet::Command)access_idx;
265        const string &cstr = temp_pkt.cmdIdxToString(cmd);
266
267        hits[access_idx]
268            .init(maxThreadsPerCPU)
269            .name(name() + "." + cstr + "_hits")
270            .desc("number of " + cstr + " hits")
271            .flags(total | nozero | nonan)
272            ;
273    }
274
275    demandHits
276        .name(name() + ".demand_hits")
277        .desc("number of demand (read+write) hits")
278        .flags(total)
279        ;
280    demandHits = hits[Packet::ReadReq] + hits[Packet::WriteReq];
281
282    overallHits
283        .name(name() + ".overall_hits")
284        .desc("number of overall hits")
285        .flags(total)
286        ;
287    overallHits = demandHits + hits[Packet::SoftPFReq] + hits[Packet::HardPFReq]
288        + hits[Packet::Writeback];
289
290    // Miss statistics
291    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
292        Packet::Command cmd = (Packet::Command)access_idx;
293        const string &cstr = temp_pkt.cmdIdxToString(cmd);
294
295        misses[access_idx]
296            .init(maxThreadsPerCPU)
297            .name(name() + "." + cstr + "_misses")
298            .desc("number of " + cstr + " misses")
299            .flags(total | nozero | nonan)
300            ;
301    }
302
303    demandMisses
304        .name(name() + ".demand_misses")
305        .desc("number of demand (read+write) misses")
306        .flags(total)
307        ;
308    demandMisses = misses[Packet::ReadReq] + misses[Packet::WriteReq];
309
310    overallMisses
311        .name(name() + ".overall_misses")
312        .desc("number of overall misses")
313        .flags(total)
314        ;
315    overallMisses = demandMisses + misses[Packet::SoftPFReq] +
316        misses[Packet::HardPFReq] + misses[Packet::Writeback];
317
318    // Miss latency statistics
319    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
320        Packet::Command cmd = (Packet::Command)access_idx;
321        const string &cstr = temp_pkt.cmdIdxToString(cmd);
322
323        missLatency[access_idx]
324            .init(maxThreadsPerCPU)
325            .name(name() + "." + cstr + "_miss_latency")
326            .desc("number of " + cstr + " miss cycles")
327            .flags(total | nozero | nonan)
328            ;
329    }
330
331    demandMissLatency
332        .name(name() + ".demand_miss_latency")
333        .desc("number of demand (read+write) miss cycles")
334        .flags(total)
335        ;
336    demandMissLatency = missLatency[Packet::ReadReq] + missLatency[Packet::WriteReq];
337
338    overallMissLatency
339        .name(name() + ".overall_miss_latency")
340        .desc("number of overall miss cycles")
341        .flags(total)
342        ;
343    overallMissLatency = demandMissLatency + missLatency[Packet::SoftPFReq] +
344        missLatency[Packet::HardPFReq];
345
346    // access formulas
347    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
348        Packet::Command cmd = (Packet::Command)access_idx;
349        const string &cstr = temp_pkt.cmdIdxToString(cmd);
350
351        accesses[access_idx]
352            .name(name() + "." + cstr + "_accesses")
353            .desc("number of " + cstr + " accesses(hits+misses)")
354            .flags(total | nozero | nonan)
355            ;
356
357        accesses[access_idx] = hits[access_idx] + misses[access_idx];
358    }
359
360    demandAccesses
361        .name(name() + ".demand_accesses")
362        .desc("number of demand (read+write) accesses")
363        .flags(total)
364        ;
365    demandAccesses = demandHits + demandMisses;
366
367    overallAccesses
368        .name(name() + ".overall_accesses")
369        .desc("number of overall (read+write) accesses")
370        .flags(total)
371        ;
372    overallAccesses = overallHits + overallMisses;
373
374    // miss rate formulas
375    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
376        Packet::Command cmd = (Packet::Command)access_idx;
377        const string &cstr = temp_pkt.cmdIdxToString(cmd);
378
379        missRate[access_idx]
380            .name(name() + "." + cstr + "_miss_rate")
381            .desc("miss rate for " + cstr + " accesses")
382            .flags(total | nozero | nonan)
383            ;
384
385        missRate[access_idx] = misses[access_idx] / accesses[access_idx];
386    }
387
388    demandMissRate
389        .name(name() + ".demand_miss_rate")
390        .desc("miss rate for demand accesses")
391        .flags(total)
392        ;
393    demandMissRate = demandMisses / demandAccesses;
394
395    overallMissRate
396        .name(name() + ".overall_miss_rate")
397        .desc("miss rate for overall accesses")
398        .flags(total)
399        ;
400    overallMissRate = overallMisses / overallAccesses;
401
402    // miss latency formulas
403    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
404        Packet::Command cmd = (Packet::Command)access_idx;
405        const string &cstr = temp_pkt.cmdIdxToString(cmd);
406
407        avgMissLatency[access_idx]
408            .name(name() + "." + cstr + "_avg_miss_latency")
409            .desc("average " + cstr + " miss latency")
410            .flags(total | nozero | nonan)
411            ;
412
413        avgMissLatency[access_idx] =
414            missLatency[access_idx] / misses[access_idx];
415    }
416
417    demandAvgMissLatency
418        .name(name() + ".demand_avg_miss_latency")
419        .desc("average overall miss latency")
420        .flags(total)
421        ;
422    demandAvgMissLatency = demandMissLatency / demandMisses;
423
424    overallAvgMissLatency
425        .name(name() + ".overall_avg_miss_latency")
426        .desc("average overall miss latency")
427        .flags(total)
428        ;
429    overallAvgMissLatency = overallMissLatency / overallMisses;
430
431    blocked_cycles.init(NUM_BLOCKED_CAUSES);
432    blocked_cycles
433        .name(name() + ".blocked_cycles")
434        .desc("number of cycles access was blocked")
435        .subname(Blocked_NoMSHRs, "no_mshrs")
436        .subname(Blocked_NoTargets, "no_targets")
437        ;
438
439
440    blocked_causes.init(NUM_BLOCKED_CAUSES);
441    blocked_causes
442        .name(name() + ".blocked")
443        .desc("number of cycles access was blocked")
444        .subname(Blocked_NoMSHRs, "no_mshrs")
445        .subname(Blocked_NoTargets, "no_targets")
446        ;
447
448    avg_blocked
449        .name(name() + ".avg_blocked_cycles")
450        .desc("average number of cycles each access was blocked")
451        .subname(Blocked_NoMSHRs, "no_mshrs")
452        .subname(Blocked_NoTargets, "no_targets")
453        ;
454
455    avg_blocked = blocked_cycles / blocked_causes;
456
457    fastWrites
458        .name(name() + ".fast_writes")
459        .desc("number of fast writes performed")
460        ;
461
462    cacheCopies
463        .name(name() + ".cache_copies")
464        .desc("number of cache copies performed")
465        ;
466
467}
468