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