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