base.cc revision 5314
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 "cpu/base.hh" 37#include "cpu/smt.hh" 38#include "mem/cache/base_cache.hh" 39#include "mem/cache/miss/mshr.hh" 40 41using namespace std; 42 43BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache, 44 const std::string &_label, 45 std::vector<Range<Addr> > filter_ranges) 46 : SimpleTimingPort(_name, _cache), cache(_cache), 47 label(_label), otherPort(NULL), 48 blocked(false), mustSendRetry(false), filterRanges(filter_ranges) 49{ 50} 51 52 53BaseCache::BaseCache(const Params *p) 54 : MemObject(p), 55 mshrQueue("MSHRs", p->mshrs, 4, MSHRQueue_MSHRs), 56 writeBuffer("write buffer", p->write_buffers, p->mshrs+1000, 57 MSHRQueue_WriteBuffer), 58 blkSize(p->block_size), 59 hitLatency(p->latency), 60 numTarget(p->tgts_per_mshr), 61 blocked(0), 62 noTargetMSHR(NULL), 63 missCount(p->max_miss_count), 64 drainEvent(NULL) 65{ 66} 67 68void 69BaseCache::CachePort::recvStatusChange(Port::Status status) 70{ 71 if (status == Port::RangeChange) { 72 otherPort->sendStatusChange(Port::RangeChange); 73 } 74} 75 76 77bool 78BaseCache::CachePort::checkFunctional(PacketPtr pkt) 79{ 80 pkt->pushLabel(label); 81 bool done = SimpleTimingPort::checkFunctional(pkt); 82 pkt->popLabel(); 83 return done; 84} 85 86 87int 88BaseCache::CachePort::deviceBlockSize() 89{ 90 return cache->getBlockSize(); 91} 92 93 94bool 95BaseCache::CachePort::recvRetryCommon() 96{ 97 assert(waitingOnRetry); 98 waitingOnRetry = false; 99 return false; 100} 101 102 103void 104BaseCache::CachePort::setBlocked() 105{ 106 assert(!blocked); 107 DPRINTF(Cache, "Cache Blocking\n"); 108 blocked = true; 109 //Clear the retry flag 110 mustSendRetry = false; 111} 112 113void 114BaseCache::CachePort::clearBlocked() 115{ 116 assert(blocked); 117 DPRINTF(Cache, "Cache Unblocking\n"); 118 blocked = false; 119 if (mustSendRetry) 120 { 121 DPRINTF(Cache, "Cache Sending Retry\n"); 122 mustSendRetry = false; 123 SendRetryEvent *ev = new SendRetryEvent(this, true); 124 // @TODO: need to find a better time (next bus cycle?) 125 ev->schedule(curTick + 1); 126 } 127} 128 129 130void 131BaseCache::init() 132{ 133 if (!cpuSidePort || !memSidePort) 134 panic("Cache not hooked up on both sides\n"); 135 cpuSidePort->sendStatusChange(Port::RangeChange); 136} 137 138 139void 140BaseCache::regStats() 141{ 142 using namespace Stats; 143 144 // Hit statistics 145 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 146 MemCmd cmd(access_idx); 147 const string &cstr = cmd.toString(); 148 149 hits[access_idx] 150 .init(maxThreadsPerCPU) 151 .name(name() + "." + cstr + "_hits") 152 .desc("number of " + cstr + " hits") 153 .flags(total | nozero | nonan) 154 ; 155 } 156 157// These macros make it easier to sum the right subset of commands and 158// to change the subset of commands that are considered "demand" vs 159// "non-demand" 160#define SUM_DEMAND(s) \ 161 (s[MemCmd::ReadReq] + s[MemCmd::WriteReq] + s[MemCmd::ReadExReq]) 162 163// should writebacks be included here? prior code was inconsistent... 164#define SUM_NON_DEMAND(s) \ 165 (s[MemCmd::SoftPFReq] + s[MemCmd::HardPFReq]) 166 167 demandHits 168 .name(name() + ".demand_hits") 169 .desc("number of demand (read+write) hits") 170 .flags(total) 171 ; 172 demandHits = SUM_DEMAND(hits); 173 174 overallHits 175 .name(name() + ".overall_hits") 176 .desc("number of overall hits") 177 .flags(total) 178 ; 179 overallHits = demandHits + SUM_NON_DEMAND(hits); 180 181 // Miss statistics 182 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 183 MemCmd cmd(access_idx); 184 const string &cstr = cmd.toString(); 185 186 misses[access_idx] 187 .init(maxThreadsPerCPU) 188 .name(name() + "." + cstr + "_misses") 189 .desc("number of " + cstr + " misses") 190 .flags(total | nozero | nonan) 191 ; 192 } 193 194 demandMisses 195 .name(name() + ".demand_misses") 196 .desc("number of demand (read+write) misses") 197 .flags(total) 198 ; 199 demandMisses = SUM_DEMAND(misses); 200 201 overallMisses 202 .name(name() + ".overall_misses") 203 .desc("number of overall misses") 204 .flags(total) 205 ; 206 overallMisses = demandMisses + SUM_NON_DEMAND(misses); 207 208 // Miss latency statistics 209 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 210 MemCmd cmd(access_idx); 211 const string &cstr = cmd.toString(); 212 213 missLatency[access_idx] 214 .init(maxThreadsPerCPU) 215 .name(name() + "." + cstr + "_miss_latency") 216 .desc("number of " + cstr + " miss cycles") 217 .flags(total | nozero | nonan) 218 ; 219 } 220 221 demandMissLatency 222 .name(name() + ".demand_miss_latency") 223 .desc("number of demand (read+write) miss cycles") 224 .flags(total) 225 ; 226 demandMissLatency = SUM_DEMAND(missLatency); 227 228 overallMissLatency 229 .name(name() + ".overall_miss_latency") 230 .desc("number of overall miss cycles") 231 .flags(total) 232 ; 233 overallMissLatency = demandMissLatency + SUM_NON_DEMAND(missLatency); 234 235 // access formulas 236 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 237 MemCmd cmd(access_idx); 238 const string &cstr = cmd.toString(); 239 240 accesses[access_idx] 241 .name(name() + "." + cstr + "_accesses") 242 .desc("number of " + cstr + " accesses(hits+misses)") 243 .flags(total | nozero | nonan) 244 ; 245 246 accesses[access_idx] = hits[access_idx] + misses[access_idx]; 247 } 248 249 demandAccesses 250 .name(name() + ".demand_accesses") 251 .desc("number of demand (read+write) accesses") 252 .flags(total) 253 ; 254 demandAccesses = demandHits + demandMisses; 255 256 overallAccesses 257 .name(name() + ".overall_accesses") 258 .desc("number of overall (read+write) accesses") 259 .flags(total) 260 ; 261 overallAccesses = overallHits + overallMisses; 262 263 // miss rate formulas 264 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 265 MemCmd cmd(access_idx); 266 const string &cstr = cmd.toString(); 267 268 missRate[access_idx] 269 .name(name() + "." + cstr + "_miss_rate") 270 .desc("miss rate for " + cstr + " accesses") 271 .flags(total | nozero | nonan) 272 ; 273 274 missRate[access_idx] = misses[access_idx] / accesses[access_idx]; 275 } 276 277 demandMissRate 278 .name(name() + ".demand_miss_rate") 279 .desc("miss rate for demand accesses") 280 .flags(total) 281 ; 282 demandMissRate = demandMisses / demandAccesses; 283 284 overallMissRate 285 .name(name() + ".overall_miss_rate") 286 .desc("miss rate for overall accesses") 287 .flags(total) 288 ; 289 overallMissRate = overallMisses / overallAccesses; 290 291 // miss latency formulas 292 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 293 MemCmd cmd(access_idx); 294 const string &cstr = cmd.toString(); 295 296 avgMissLatency[access_idx] 297 .name(name() + "." + cstr + "_avg_miss_latency") 298 .desc("average " + cstr + " miss latency") 299 .flags(total | nozero | nonan) 300 ; 301 302 avgMissLatency[access_idx] = 303 missLatency[access_idx] / misses[access_idx]; 304 } 305 306 demandAvgMissLatency 307 .name(name() + ".demand_avg_miss_latency") 308 .desc("average overall miss latency") 309 .flags(total) 310 ; 311 demandAvgMissLatency = demandMissLatency / demandMisses; 312 313 overallAvgMissLatency 314 .name(name() + ".overall_avg_miss_latency") 315 .desc("average overall miss latency") 316 .flags(total) 317 ; 318 overallAvgMissLatency = overallMissLatency / overallMisses; 319 320 blocked_cycles.init(NUM_BLOCKED_CAUSES); 321 blocked_cycles 322 .name(name() + ".blocked_cycles") 323 .desc("number of cycles access was blocked") 324 .subname(Blocked_NoMSHRs, "no_mshrs") 325 .subname(Blocked_NoTargets, "no_targets") 326 ; 327 328 329 blocked_causes.init(NUM_BLOCKED_CAUSES); 330 blocked_causes 331 .name(name() + ".blocked") 332 .desc("number of cycles access was blocked") 333 .subname(Blocked_NoMSHRs, "no_mshrs") 334 .subname(Blocked_NoTargets, "no_targets") 335 ; 336 337 avg_blocked 338 .name(name() + ".avg_blocked_cycles") 339 .desc("average number of cycles each access was blocked") 340 .subname(Blocked_NoMSHRs, "no_mshrs") 341 .subname(Blocked_NoTargets, "no_targets") 342 ; 343 344 avg_blocked = blocked_cycles / blocked_causes; 345 346 fastWrites 347 .name(name() + ".fast_writes") 348 .desc("number of fast writes performed") 349 ; 350 351 cacheCopies 352 .name(name() + ".cache_copies") 353 .desc("number of cache copies performed") 354 ; 355 356 writebacks 357 .init(maxThreadsPerCPU) 358 .name(name() + ".writebacks") 359 .desc("number of writebacks") 360 .flags(total) 361 ; 362 363 // MSHR statistics 364 // MSHR hit statistics 365 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 366 MemCmd cmd(access_idx); 367 const string &cstr = cmd.toString(); 368 369 mshr_hits[access_idx] 370 .init(maxThreadsPerCPU) 371 .name(name() + "." + cstr + "_mshr_hits") 372 .desc("number of " + cstr + " MSHR hits") 373 .flags(total | nozero | nonan) 374 ; 375 } 376 377 demandMshrHits 378 .name(name() + ".demand_mshr_hits") 379 .desc("number of demand (read+write) MSHR hits") 380 .flags(total) 381 ; 382 demandMshrHits = SUM_DEMAND(mshr_hits); 383 384 overallMshrHits 385 .name(name() + ".overall_mshr_hits") 386 .desc("number of overall MSHR hits") 387 .flags(total) 388 ; 389 overallMshrHits = demandMshrHits + SUM_NON_DEMAND(mshr_hits); 390 391 // MSHR miss statistics 392 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 393 MemCmd cmd(access_idx); 394 const string &cstr = cmd.toString(); 395 396 mshr_misses[access_idx] 397 .init(maxThreadsPerCPU) 398 .name(name() + "." + cstr + "_mshr_misses") 399 .desc("number of " + cstr + " MSHR misses") 400 .flags(total | nozero | nonan) 401 ; 402 } 403 404 demandMshrMisses 405 .name(name() + ".demand_mshr_misses") 406 .desc("number of demand (read+write) MSHR misses") 407 .flags(total) 408 ; 409 demandMshrMisses = SUM_DEMAND(mshr_misses); 410 411 overallMshrMisses 412 .name(name() + ".overall_mshr_misses") 413 .desc("number of overall MSHR misses") 414 .flags(total) 415 ; 416 overallMshrMisses = demandMshrMisses + SUM_NON_DEMAND(mshr_misses); 417 418 // MSHR miss latency statistics 419 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 420 MemCmd cmd(access_idx); 421 const string &cstr = cmd.toString(); 422 423 mshr_miss_latency[access_idx] 424 .init(maxThreadsPerCPU) 425 .name(name() + "." + cstr + "_mshr_miss_latency") 426 .desc("number of " + cstr + " MSHR miss cycles") 427 .flags(total | nozero | nonan) 428 ; 429 } 430 431 demandMshrMissLatency 432 .name(name() + ".demand_mshr_miss_latency") 433 .desc("number of demand (read+write) MSHR miss cycles") 434 .flags(total) 435 ; 436 demandMshrMissLatency = SUM_DEMAND(mshr_miss_latency); 437 438 overallMshrMissLatency 439 .name(name() + ".overall_mshr_miss_latency") 440 .desc("number of overall MSHR miss cycles") 441 .flags(total) 442 ; 443 overallMshrMissLatency = 444 demandMshrMissLatency + SUM_NON_DEMAND(mshr_miss_latency); 445 446 // MSHR uncacheable statistics 447 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 448 MemCmd cmd(access_idx); 449 const string &cstr = cmd.toString(); 450 451 mshr_uncacheable[access_idx] 452 .init(maxThreadsPerCPU) 453 .name(name() + "." + cstr + "_mshr_uncacheable") 454 .desc("number of " + cstr + " MSHR uncacheable") 455 .flags(total | nozero | nonan) 456 ; 457 } 458 459 overallMshrUncacheable 460 .name(name() + ".overall_mshr_uncacheable_misses") 461 .desc("number of overall MSHR uncacheable misses") 462 .flags(total) 463 ; 464 overallMshrUncacheable = 465 SUM_DEMAND(mshr_uncacheable) + SUM_NON_DEMAND(mshr_uncacheable); 466 467 // MSHR miss latency statistics 468 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 469 MemCmd cmd(access_idx); 470 const string &cstr = cmd.toString(); 471 472 mshr_uncacheable_lat[access_idx] 473 .init(maxThreadsPerCPU) 474 .name(name() + "." + cstr + "_mshr_uncacheable_latency") 475 .desc("number of " + cstr + " MSHR uncacheable cycles") 476 .flags(total | nozero | nonan) 477 ; 478 } 479 480 overallMshrUncacheableLatency 481 .name(name() + ".overall_mshr_uncacheable_latency") 482 .desc("number of overall MSHR uncacheable cycles") 483 .flags(total) 484 ; 485 overallMshrUncacheableLatency = 486 SUM_DEMAND(mshr_uncacheable_lat) + 487 SUM_NON_DEMAND(mshr_uncacheable_lat); 488 489#if 0 490 // MSHR access formulas 491 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 492 MemCmd cmd(access_idx); 493 const string &cstr = cmd.toString(); 494 495 mshrAccesses[access_idx] 496 .name(name() + "." + cstr + "_mshr_accesses") 497 .desc("number of " + cstr + " mshr accesses(hits+misses)") 498 .flags(total | nozero | nonan) 499 ; 500 mshrAccesses[access_idx] = 501 mshr_hits[access_idx] + mshr_misses[access_idx] 502 + mshr_uncacheable[access_idx]; 503 } 504 505 demandMshrAccesses 506 .name(name() + ".demand_mshr_accesses") 507 .desc("number of demand (read+write) mshr accesses") 508 .flags(total | nozero | nonan) 509 ; 510 demandMshrAccesses = demandMshrHits + demandMshrMisses; 511 512 overallMshrAccesses 513 .name(name() + ".overall_mshr_accesses") 514 .desc("number of overall (read+write) mshr accesses") 515 .flags(total | nozero | nonan) 516 ; 517 overallMshrAccesses = overallMshrHits + overallMshrMisses 518 + overallMshrUncacheable; 519#endif 520 521 // MSHR miss rate formulas 522 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 523 MemCmd cmd(access_idx); 524 const string &cstr = cmd.toString(); 525 526 mshrMissRate[access_idx] 527 .name(name() + "." + cstr + "_mshr_miss_rate") 528 .desc("mshr miss rate for " + cstr + " accesses") 529 .flags(total | nozero | nonan) 530 ; 531 532 mshrMissRate[access_idx] = 533 mshr_misses[access_idx] / accesses[access_idx]; 534 } 535 536 demandMshrMissRate 537 .name(name() + ".demand_mshr_miss_rate") 538 .desc("mshr miss rate for demand accesses") 539 .flags(total) 540 ; 541 demandMshrMissRate = demandMshrMisses / demandAccesses; 542 543 overallMshrMissRate 544 .name(name() + ".overall_mshr_miss_rate") 545 .desc("mshr miss rate for overall accesses") 546 .flags(total) 547 ; 548 overallMshrMissRate = overallMshrMisses / overallAccesses; 549 550 // mshrMiss latency formulas 551 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 552 MemCmd cmd(access_idx); 553 const string &cstr = cmd.toString(); 554 555 avgMshrMissLatency[access_idx] 556 .name(name() + "." + cstr + "_avg_mshr_miss_latency") 557 .desc("average " + cstr + " mshr miss latency") 558 .flags(total | nozero | nonan) 559 ; 560 561 avgMshrMissLatency[access_idx] = 562 mshr_miss_latency[access_idx] / mshr_misses[access_idx]; 563 } 564 565 demandAvgMshrMissLatency 566 .name(name() + ".demand_avg_mshr_miss_latency") 567 .desc("average overall mshr miss latency") 568 .flags(total) 569 ; 570 demandAvgMshrMissLatency = demandMshrMissLatency / demandMshrMisses; 571 572 overallAvgMshrMissLatency 573 .name(name() + ".overall_avg_mshr_miss_latency") 574 .desc("average overall mshr miss latency") 575 .flags(total) 576 ; 577 overallAvgMshrMissLatency = overallMshrMissLatency / overallMshrMisses; 578 579 // mshrUncacheable latency formulas 580 for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { 581 MemCmd cmd(access_idx); 582 const string &cstr = cmd.toString(); 583 584 avgMshrUncacheableLatency[access_idx] 585 .name(name() + "." + cstr + "_avg_mshr_uncacheable_latency") 586 .desc("average " + cstr + " mshr uncacheable latency") 587 .flags(total | nozero | nonan) 588 ; 589 590 avgMshrUncacheableLatency[access_idx] = 591 mshr_uncacheable_lat[access_idx] / mshr_uncacheable[access_idx]; 592 } 593 594 overallAvgMshrUncacheableLatency 595 .name(name() + ".overall_avg_mshr_uncacheable_latency") 596 .desc("average overall mshr uncacheable latency") 597 .flags(total) 598 ; 599 overallAvgMshrUncacheableLatency = overallMshrUncacheableLatency / overallMshrUncacheable; 600 601 mshr_cap_events 602 .init(maxThreadsPerCPU) 603 .name(name() + ".mshr_cap_events") 604 .desc("number of times MSHR cap was activated") 605 .flags(total) 606 ; 607 608 //software prefetching stats 609 soft_prefetch_mshr_full 610 .init(maxThreadsPerCPU) 611 .name(name() + ".soft_prefetch_mshr_full") 612 .desc("number of mshr full events for SW prefetching instrutions") 613 .flags(total) 614 ; 615 616 mshr_no_allocate_misses 617 .name(name() +".no_allocate_misses") 618 .desc("Number of misses that were no-allocate") 619 ; 620 621} 622 623unsigned int 624BaseCache::drain(Event *de) 625{ 626 int count = memSidePort->drain(de) + cpuSidePort->drain(de); 627 628 // Set status 629 if (count != 0) { 630 drainEvent = de; 631 632 changeState(SimObject::Draining); 633 return count; 634 } 635 636 changeState(SimObject::Drained); 637 return 0; 638} 639