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