1/* 2 * Copyright (c) 2011-2014, 2017 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software --- 23 unchanged lines hidden (view full) --- 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Dam Sunwoo 38 * Matt Horsnell 39 * Andreas Sandberg |
40 * Jose Marinho |
41 */ 42 43#include "arch/arm/pmu.hh" 44 45#include "arch/arm/isa.hh" 46#include "arch/arm/utility.hh" 47#include "base/trace.hh" 48#include "cpu/base.hh" 49#include "debug/Checkpoint.hh" 50#include "debug/PMUVerbose.hh" 51#include "dev/arm/base_gic.hh" |
52#include "dev/arm/generic_timer.hh" |
53#include "dev/arm/realview.hh" 54#include "params/ArmPMU.hh" 55 56namespace ArmISA { 57 58const MiscReg PMU::reg_pmcr_wr_mask = 0x39; 59 60PMU::PMU(const ArmPMUParams *p) 61 : SimObject(p), BaseISADevice(), 62 reg_pmcnten(0), reg_pmcr(0), 63 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0), 64 reg_pmceid0(0),reg_pmceid1(0), 65 clock_remainder(0), |
66 maximumCounterCount(p->eventCounters), 67 cycleCounter(*this, maximumCounterCount), 68 cycleCounterEventId(p->cycleEventId), 69 swIncrementEvent(nullptr), |
70 reg_pmcr_conf(0), 71 pmuInterrupt(p->pmuInterrupt), 72 platform(p->platform) 73{ 74 DPRINTF(PMUVerbose, "Initializing the PMU.\n"); 75 |
76 if (maximumCounterCount > 31) { |
77 fatal("The PMU can only accept 31 counters, %d counters requested.\n", |
78 maximumCounterCount); |
79 } 80 81 /* Setup the performance counter ID registers */ 82 reg_pmcr_conf.imp = 0x41; // ARM Ltd. 83 reg_pmcr_conf.idcode = 0x00; 84 reg_pmcr_conf.n = p->eventCounters; 85 86 // Setup the hard-coded cycle counter, which is equivalent to 87 // architected counter event type 0x11. 88 cycleCounter.eventId = 0x11; 89} 90 91PMU::~PMU() 92{ 93} 94 95void |
96PMU::addSoftwareIncrementEvent(unsigned int id) 97{ 98 auto old_event = eventMap.find(id); 99 DPRINTF(PMUVerbose, "PMU: Adding SW increment event with id '0x%x'\n", id); 100 101 if (swIncrementEvent) { 102 fatal_if(old_event == eventMap.end() || 103 old_event->second != swIncrementEvent, 104 "Trying to add a software increment event with multiple" 105 "IDs. This is not supported.\n"); 106 return; 107 } 108 109 fatal_if(old_event != eventMap.end(), "An event with id %d has " 110 "been previously defined\n", id); 111 112 swIncrementEvent = new SWIncrementEvent(); 113 eventMap[id] = swIncrementEvent; 114 registerEvent(id); 115} 116 117void |
118PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name) 119{ |
120 |
121 DPRINTF(PMUVerbose, "PMU: Adding Probe Driven event with id '0x%x'" 122 "as probe %s:%s\n",id, obj->name(), probe_name); 123 124 RegularEvent *event = nullptr; 125 auto event_entry = eventMap.find(id); 126 if (event_entry == eventMap.end()) { 127 128 event = new RegularEvent(); 129 eventMap[id] = event; 130 131 } else { 132 event = dynamic_cast<RegularEvent*>(event_entry->second); 133 if (!event) { 134 fatal("Event with id %d is not probe driven\n", id); 135 } 136 } 137 event->addMicroarchitectureProbe(obj, probe_name); 138 139 registerEvent(id); 140 141} 142 143void 144PMU::registerEvent(uint32_t id) 145{ |
146 // Flag the event as available in the corresponding PMCEID register if it 147 // is an architected event. 148 if (id < 0x20) { 149 reg_pmceid0 |= ((uint64_t)1) << id; 150 } else if (id > 0x20 && id < 0x40) { 151 reg_pmceid1 |= ((uint64_t)1) << (id - 0x20); 152 } else if (id >= 0x4000 && id < 0x4020) { 153 reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32); --- 5 unchanged lines hidden (view full) --- 159void 160PMU::drainResume() 161{ 162 // Re-attach enabled counters after a resume in case they changed. 163 updateAllCounters(); 164} 165 166void |
167PMU::regProbeListeners() 168{ 169 170 // at this stage all probe configurations are done 171 // counters can be configured 172 for (uint32_t index = 0; index < maximumCounterCount-1; index++) { 173 counters.emplace_back(*this, index); 174 } 175 176 PMUEvent *event = getEvent(cycleCounterEventId); 177 panic_if(!event, "core cycle event is not present\n"); 178 cycleCounter.enabled = true; 179 cycleCounter.attach(event); 180} 181 182void |
183PMU::setMiscReg(int misc_reg, MiscReg val) 184{ 185 DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n", 186 miscRegName[unflattenMiscReg(misc_reg)], val); 187 188 switch (unflattenMiscReg(misc_reg)) { 189 case MISCREG_PMCR_EL0: 190 case MISCREG_PMCR: --- 14 unchanged lines hidden (view full) --- 205 206 case MISCREG_PMOVSCLR_EL0: 207 case MISCREG_PMOVSR: 208 reg_pmovsr &= ~val; 209 return; 210 211 case MISCREG_PMSWINC_EL0: 212 case MISCREG_PMSWINC: |
213 if (swIncrementEvent) { 214 swIncrementEvent->write(val); |
215 } |
216 return; |
217 218 case MISCREG_PMCCNTR_EL0: 219 case MISCREG_PMCCNTR: |
220 cycleCounter.setValue(val); |
221 return; 222 223 case MISCREG_PMSELR_EL0: 224 case MISCREG_PMSELR: 225 reg_pmselr = val; 226 return; 227 //TODO: implement MISCREF_PMCEID{2,3} 228 case MISCREG_PMCEID0_EL0: --- 105 unchanged lines hidden (view full) --- 334 //TODO: implement MISCREF_PMCEID{2,3} 335 case MISCREG_PMCEID0: // Common Event ID register 336 return reg_pmceid0 & 0xFFFFFFFF; 337 338 case MISCREG_PMCEID1: // Common Event ID register 339 return reg_pmceid1 & 0xFFFFFFFF; 340 341 case MISCREG_PMCCNTR_EL0: |
342 return cycleCounter.getValue(); |
343 344 case MISCREG_PMCCNTR: |
345 return cycleCounter.getValue() & 0xFFFFFFFF; |
346 347 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 348 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0); 349 350 case MISCREG_PMCCFILTR: 351 case MISCREG_PMCCFILTR_EL0: 352 return getCounterTypeRegister(PMCCNTR); 353 354 case MISCREG_PMXEVTYPER_PMCCFILTR: 355 case MISCREG_PMXEVTYPER_EL0: 356 case MISCREG_PMXEVTYPER: 357 return getCounterTypeRegister(reg_pmselr.sel); 358 |
359 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: { 360 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 361 0xFFFFFFFF; |
362 |
363 } 364 |
365 case MISCREG_PMXEVCNTR_EL0: 366 case MISCREG_PMXEVCNTR: 367 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF; 368 369 case MISCREG_PMUSERENR_EL0: 370 case MISCREG_PMUSERENR: 371 // TODO 372 return 0; --- 20 unchanged lines hidden (view full) --- 393 394 if (val.p) { 395 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n"); 396 resetEventCounts(); 397 } 398 399 if (val.c) { 400 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n"); |
401 cycleCounter.setValue(0); |
402 } 403 404 // Reset the clock remainder if divide by 64-mode is toggled. 405 if (reg_pmcr.d != val.d) 406 clock_remainder = 0; 407 408 reg_pmcr = val & reg_pmcr_wr_mask; 409 updateAllCounters(); --- 4 unchanged lines hidden (view full) --- 414{ 415 const bool global_enable(reg_pmcr.e); 416 417 for (int i = 0; i < counters.size(); ++i) { 418 CounterState &ctr(counters[i]); 419 const bool enable(global_enable && (reg_pmcnten & (1 << i))); 420 if (ctr.enabled != enable) { 421 ctr.enabled = enable; |
422 updateCounter(ctr); |
423 } 424 } 425 426 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR))); 427 if (cycleCounter.enabled != ccntr_enable) { 428 cycleCounter.enabled = ccntr_enable; |
429 updateCounter(cycleCounter); |
430 } 431} 432 |
433void 434PMU::PMUEvent::attachEvent(PMU::CounterState *user) 435{ 436 if (userCounters.empty()) { 437 enable(); 438 } 439 userCounters.insert(user); 440 updateAttachedCounters(); 441} 442 443void 444PMU::PMUEvent::increment(const uint64_t val) 445{ 446 for (auto& counter: userCounters) { 447 counter->add(val); 448 } 449} 450 451void 452PMU::PMUEvent::detachEvent(PMU::CounterState *user) 453{ 454 userCounters.erase(user); 455 456 if (userCounters.empty()) { 457 disable(); 458 } 459} 460 461void 462PMU::RegularEvent::RegularProbe::notify(const uint64_t &val) 463{ 464 parentEvent->increment(val); 465} 466 467void 468PMU::RegularEvent::enable() 469{ 470 for (auto& subEvents: microArchitectureEventSet) { 471 attachedProbePointList.emplace_back( 472 new RegularProbe(this, subEvents.first, subEvents.second)); 473 } 474} 475 476void 477PMU::RegularEvent::disable() 478{ 479 attachedProbePointList.clear(); 480} 481 |
482bool |
483PMU::CounterState::isFiltered() const |
484{ |
485 assert(pmu.isa); |
486 |
487 const PMEVTYPER_t filter(this->filter); 488 const SCR scr(pmu.isa->readMiscRegNoEffect(MISCREG_SCR)); 489 const CPSR cpsr(pmu.isa->readMiscRegNoEffect(MISCREG_CPSR)); |
490 const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode)); 491 const bool secure(inSecureState(scr, cpsr)); 492 493 switch (el) { 494 case EL0: 495 return secure ? filter.u : (filter.u != filter.nsu); 496 497 case EL1: --- 6 unchanged lines hidden (view full) --- 504 return filter.p != filter.m; 505 506 default: 507 panic("Unexpected execution level in PMU::isFiltered.\n"); 508 } 509} 510 511void |
512PMU::CounterState::detach() |
513{ |
514 if (sourceEvent) { 515 sourceEvent->detachEvent(this); 516 sourceEvent = nullptr; 517 } else { 518 debugCounter("detaching event not currently attached" 519 " to any event\n"); 520 } 521} |
522 |
523void 524PMU::CounterState::attach(PMUEvent* event) 525{ 526 value = 0; 527 sourceEvent = event; 528 sourceEvent->attachEvent(this); 529} |
530 |
531uint64_t 532PMU::CounterState::getValue() const 533{ 534 if (sourceEvent) { 535 sourceEvent->updateAttachedCounters(); 536 } else { 537 debugCounter("attempted to get value from a counter without" 538 " an associated event\n"); |
539 } |
540 return value; 541} |
542 |
543void 544PMU::CounterState::setValue(uint64_t val) 545{ 546 value = val; 547 resetValue = true; 548 549 if (sourceEvent) { 550 sourceEvent->updateAttachedCounters(); 551 } else { 552 debugCounter("attempted to set value from a counter without" 553 " an associated event\n"); |
554 } 555} 556 557void |
558PMU::updateCounter(CounterState &ctr) |
559{ 560 if (!ctr.enabled) { |
561 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", 562 ctr.getCounterId()); 563 ctr.detach(); 564 |
565 } else { 566 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n", |
567 ctr.getCounterId(), ctr.eventId); |
568 |
569 auto sourceEvent = eventMap.find(ctr.eventId); 570 if (sourceEvent == eventMap.end()) { |
571 warn("Can't enable PMU counter of type '0x%x': " 572 "No such event type.\n", ctr.eventId); |
573 } else { 574 ctr.attach(sourceEvent->second); |
575 } 576 } 577} 578 579 580void 581PMU::resetEventCounts() 582{ 583 for (CounterState &ctr : counters) |
584 ctr.setValue(0); |
585} 586 587void 588PMU::setCounterValue(CounterId id, uint64_t val) 589{ 590 if (!isValidCounter(id)) { 591 warn_once("Can't change counter value: Counter %i does not exist.\n", 592 id); 593 return; 594 } 595 596 CounterState &ctr(getCounter(id)); |
597 ctr.setValue(val); |
598} 599 600PMU::PMEVTYPER_t 601PMU::getCounterTypeRegister(CounterId id) const 602{ 603 if (!isValidCounter(id)) 604 return 0; 605 --- 20 unchanged lines hidden (view full) --- 626 627 ctr.filter = val; 628 629 // If PMCCNTR Register, do not change event type. PMCCNTR can 630 // count processor cycles only. If we change the event type, we 631 // need to update the probes the counter is using. 632 if (id != PMCCNTR && old_event_id != val.evtCount) { 633 ctr.eventId = val.evtCount; |
634 updateCounter(ctr); |
635 } 636} 637 638void 639PMU::raiseInterrupt() 640{ 641 RealView *rv(dynamic_cast<RealView *>(platform)); 642 if (!rv || !rv->gic) { --- 48 unchanged lines hidden (view full) --- 691 UNSERIALIZE_SCALAR(clock_remainder); 692 693 for (size_t i = 0; i < counters.size(); ++i) 694 counters[i].unserializeSection(cp, csprintf("counters.%i", i)); 695 696 cycleCounter.unserializeSection(cp, "cycleCounter"); 697} 698 |
699PMU::PMUEvent* 700PMU::getEvent(uint64_t eventId) 701{ 702 auto entry = eventMap.find(eventId); 703 704 if (entry == eventMap.end()) { 705 warn("event %d does not exist\n", eventId); 706 return nullptr; 707 } else { 708 return entry->second; 709 } 710} 711 |
712void 713PMU::CounterState::serialize(CheckpointOut &cp) const 714{ 715 SERIALIZE_SCALAR(eventId); 716 SERIALIZE_SCALAR(value); 717 SERIALIZE_SCALAR(overflow64); 718} 719 720void 721PMU::CounterState::unserialize(CheckpointIn &cp) 722{ 723 UNSERIALIZE_SCALAR(eventId); 724 UNSERIALIZE_SCALAR(value); 725 UNSERIALIZE_SCALAR(overflow64); 726} 727 |
728uint64_t |
729PMU::CounterState::add(uint64_t delta) 730{ |
731 uint64_t value_until_overflow; 732 if (overflow64) { 733 value_until_overflow = UINT64_MAX - value; 734 } else { 735 value_until_overflow = UINT32_MAX - (uint32_t)value; 736 } |
737 |
738 if (isFiltered()) 739 return value_until_overflow; |
740 |
741 if (resetValue) { 742 delta = 0; 743 resetValue = false; 744 } else { 745 value += delta; 746 } 747 748 if (delta > value_until_overflow) { 749 750 // overflow situation detected 751 // flag the overflow occurence 752 pmu.reg_pmovsr |= (1 << counterId); 753 754 // Deliver a PMU interrupt if interrupt delivery is enabled 755 // for this counter. 756 if (pmu.reg_pminten & (1 << counterId)) { 757 pmu.raiseInterrupt(); 758 } 759 return overflow64 ? UINT64_MAX : UINT32_MAX; 760 } 761 return value_until_overflow - delta + 1; |
762} 763 |
764void 765PMU::SWIncrementEvent::write(uint64_t val) 766{ 767 for (auto& counter: userCounters) { 768 if (val & (0x1 << counter->getCounterId())) { 769 counter->add(1); 770 } 771 } 772} 773 |
774} // namespace ArmISA 775 776ArmISA::PMU * 777ArmPMUParams::create() 778{ 779 return new ArmISA::PMU(this); 780} |