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