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