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