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