Index: tools/llvm-mca/Backend.h =================================================================== --- tools/llvm-mca/Backend.h +++ tools/llvm-mca/Backend.h @@ -23,6 +23,7 @@ namespace mca { class HWEventListener; +class HWInstructionEvent; /// \brief An out of order backend for a specific subtarget. /// @@ -71,6 +72,7 @@ RegisterFileSize, MaxRetirePerCycle, DispatchWidth, HWS.get())), SM(Source), Cycles(0) { IB = llvm::make_unique(MCII, getProcResourceMasks()); + HWS->setDispatchUnit(DU.get()); } void run() { @@ -80,6 +82,8 @@ unsigned getNumIterations() const { return SM.getNumIterations(); } unsigned getNumInstructions() const { return SM.size(); } + const Instruction& getInstruction(unsigned Index) const { return *Instructions.find(Index)->second; } + void eraseInstruction(unsigned Index) { Instructions.erase(Index); } unsigned getNumCycles() const { return Cycles; } unsigned getTotalRegisterMappingsCreated() const { return DU->getTotalRegisterMappingsCreated(); @@ -125,14 +129,8 @@ void addEventListener(HWEventListener *Listener); void notifyCycleBegin(unsigned Cycle); - void notifyInstructionDispatched(unsigned Index); - void notifyInstructionReady(unsigned Index); - void notifyInstructionIssued( - unsigned Index, - const llvm::ArrayRef> &Used); - void notifyInstructionExecuted(unsigned Index); + void notifyInstructionEvent(const HWInstructionEvent& Event); void notifyResourceAvailable(const ResourceRef &RR); - void notifyInstructionRetired(unsigned Index); void notifyCycleEnd(unsigned Cycle); }; Index: tools/llvm-mca/Backend.cpp =================================================================== --- tools/llvm-mca/Backend.cpp +++ tools/llvm-mca/Backend.cpp @@ -65,50 +65,9 @@ HWS->cycleEvent(Cycle); } -void Backend::notifyInstructionDispatched(unsigned Index) { - DEBUG(dbgs() << "[E] Instruction Dispatched: " << Index << '\n'); +void Backend::notifyInstructionEvent(const HWInstructionEvent& Event) { for (HWEventListener *Listener : Listeners) - Listener->onInstructionDispatched(Index); -} - -void Backend::notifyInstructionReady(unsigned Index) { - DEBUG(dbgs() << "[E] Instruction Ready: " << Index << '\n'); - for (HWEventListener *Listener : Listeners) - Listener->onInstructionReady(Index); -} - -void Backend::notifyInstructionIssued( - unsigned Index, const ArrayRef> &Used) { - DEBUG( - dbgs() << "[E] Instruction Issued: " << Index << '\n'; - for (const std::pair &Resource : Used) { - dbgs() << "[E] Resource Used: [" << Resource.first.first << '.' - << Resource.first.second << "]\n"; - dbgs() << " cycles: " << Resource.second << '\n'; - } - ); - - for (HWEventListener *Listener : Listeners) - Listener->onInstructionIssued(Index, Used); -} - -void Backend::notifyInstructionExecuted(unsigned Index) { - DEBUG(dbgs() << "[E] Instruction Executed: " << Index << '\n'); - for (HWEventListener *Listener : Listeners) - Listener->onInstructionExecuted(Index); - - const Instruction &IS = *Instructions[Index]; - DU->onInstructionExecuted(IS.getRCUTokenID()); -} - -void Backend::notifyInstructionRetired(unsigned Index) { - DEBUG(dbgs() << "[E] Instruction Retired: " << Index << '\n'); - for (HWEventListener *Listener : Listeners) - Listener->onInstructionRetired(Index); - - const Instruction &IS = *Instructions[Index]; - DU->invalidateRegisterMappings(IS); - Instructions.erase(Index); + Listener->onInstructionEvent(Event); } void Backend::notifyResourceAvailable(const ResourceRef &RR) { Index: tools/llvm-mca/BackendStatistics.h =================================================================== --- tools/llvm-mca/BackendStatistics.h +++ tools/llvm-mca/BackendStatistics.h @@ -110,25 +110,17 @@ BackendStatistics(const Backend &backend) : B(backend), NumDispatched(0), NumIssued(0), NumRetired(0) {} - void onInstructionDispatched(unsigned Index) override { NumDispatched++; } - void - onInstructionIssued(unsigned Index, - const llvm::ArrayRef> - & /* unused */) override { - NumIssued++; - } - void onInstructionRetired(unsigned Index) override { NumRetired++; } + void onInstructionEvent(const HWInstructionEvent& Event) override; void onCycleBegin(unsigned Cycle) override { NumCycles++; } void onCycleEnd(unsigned Cycle) override { updateHistograms(); } void printView(llvm::raw_ostream &OS) const override { - printDispatchStalls(OS, B.getNumRATStalls(), B.getNumRCUStalls(), - B.getNumSQStalls(), B.getNumLDQStalls(), - B.getNumSTQStalls(), B.getNumDispatchGroupStalls()); + printDispatchStalls(OS, B.getNumRATStalls(), B.getNumRCUStalls(), B.getNumSQStalls(), + B.getNumLDQStalls(), B.getNumSTQStalls(), B.getNumDispatchGroupStalls()); printRATStatistics(OS, B.getTotalRegisterMappingsCreated(), - B.getMaxUsedRegisterMappings()); + B.getMaxUsedRegisterMappings()); printDispatchUnitStatistics(OS); printSchedulerStatistics(OS); printRetireUnitStatistics(OS); Index: tools/llvm-mca/BackendStatistics.cpp =================================================================== --- tools/llvm-mca/BackendStatistics.cpp +++ tools/llvm-mca/BackendStatistics.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// /// \file -/// +/// /// Functionalities used by the BackendPrinter to print out histograms /// related to number of {dispatch/issue/retire} per number of cycles. /// @@ -20,6 +20,22 @@ namespace mca { +void BackendStatistics::onInstructionEvent(const HWInstructionEvent& Event) { + switch (Event.Type) { + case HWInstructionEvent::Retired: + ++NumRetired; + break; + case HWInstructionEvent::Issued: + ++NumIssued; + break; + case HWInstructionEvent::Dispatched: + ++NumDispatched; + break; + default: + break; + } +} + void BackendStatistics::printRetireUnitStatistics(llvm::raw_ostream &OS) const { std::string Buffer; raw_string_ostream TempStream(Buffer); @@ -42,8 +58,7 @@ OS << Buffer; } -void BackendStatistics::printDispatchUnitStatistics( - llvm::raw_ostream &OS) const { +void BackendStatistics::printDispatchUnitStatistics(llvm::raw_ostream &OS) const { std::string Buffer; raw_string_ostream TempStream(Buffer); TempStream << "\n\nDispatch Logic - " @@ -77,8 +92,8 @@ } void BackendStatistics::printRATStatistics(raw_ostream &OS, - unsigned TotalMappings, - unsigned MaxUsedMappings) const { + unsigned TotalMappings, + unsigned MaxUsedMappings) const { std::string Buffer; raw_string_ostream TempStream(Buffer); TempStream << "\n\nRegister Alias Table:"; @@ -89,12 +104,11 @@ OS << Buffer; } -void BackendStatistics::printDispatchStalls(raw_ostream &OS, unsigned RATStalls, - unsigned RCUStalls, - unsigned SCHEDQStalls, - unsigned LDQStalls, - unsigned STQStalls, - unsigned DGStalls) const { +void BackendStatistics::printDispatchStalls(raw_ostream &OS, + unsigned RATStalls, unsigned RCUStalls, + unsigned SCHEDQStalls, + unsigned LDQStalls, unsigned STQStalls, + unsigned DGStalls) const { std::string Buffer; raw_string_ostream TempStream(Buffer); TempStream << "\n\nDynamic Dispatch Stall Cycles:\n"; @@ -115,9 +129,8 @@ OS << Buffer; } -void BackendStatistics::printSchedulerUsage( - raw_ostream &OS, const MCSchedModel &SM, - const ArrayRef &Usage) const { +void BackendStatistics::printSchedulerUsage(raw_ostream &OS, + const MCSchedModel &SM, const ArrayRef &Usage) const { std::string Buffer; raw_string_ostream TempStream(Buffer); TempStream << "\n\nScheduler's queue usage:\n"; @@ -138,3 +151,4 @@ } } // namespace mca + Index: tools/llvm-mca/Dispatch.cpp =================================================================== --- tools/llvm-mca/Dispatch.cpp +++ tools/llvm-mca/Dispatch.cpp @@ -15,6 +15,7 @@ #include "Dispatch.h" #include "Backend.h" +#include "HWEventListener.h" #include "Scheduler.h" #include "llvm/Support/Debug.h" @@ -150,11 +151,17 @@ } void DispatchUnit::notifyInstructionDispatched(unsigned Index) { - Owner->notifyInstructionDispatched(Index); + DEBUG(dbgs() << "[E] Instruction Dispatched: " << Index << '\n'); + Owner->notifyInstructionEvent(HWInstructionEvent(HWInstructionEvent::Dispatched, Index)); } void DispatchUnit::notifyInstructionRetired(unsigned Index) { - Owner->notifyInstructionRetired(Index); + DEBUG(dbgs() << "[E] Instruction Retired: " << Index << '\n'); + Owner->notifyInstructionEvent(HWInstructionEvent(HWInstructionEvent::Retired, Index)); + + const Instruction &IS = Owner->getInstruction(Index); + invalidateRegisterMappings(IS); + Owner->eraseInstruction(Index); } void RetireControlUnit::cycleEvent() { @@ -243,7 +250,7 @@ // Reserve slots in the RCU. unsigned RCUTokenID = RCU->reserveSlot(IID, NumMicroOps); NewInst->setRCUTokenID(RCUTokenID); - Owner->notifyInstructionDispatched(IID); + notifyInstructionDispatched(IID); SC->scheduleInstruction(IID, NewInst); return RCUTokenID; Index: tools/llvm-mca/HWEventListener.h =================================================================== --- tools/llvm-mca/HWEventListener.h +++ tools/llvm-mca/HWEventListener.h @@ -21,28 +21,53 @@ namespace mca { -class HWEventListener { +// An event +class HWInstructionEvent { public: - // Events generated by the Retire Control Unit. - virtual void onInstructionRetired(unsigned Index) {}; + // FIXME: This should be subtarget-specific. Move to TD files. + enum EventType { + Invalid = 0, + // Events generated by the Retire Control Unit. + Retired, + // Events generated by the Scheduler. + Ready, + Issued, + Executed, + // Events generated by the Dispatch logic. + Dispatched, + }; + + HWInstructionEvent(unsigned Type, unsigned Index) : Type(Type), Index(Index) {} + + // The event type. The exact meaning depends on the subtarget, + const unsigned Type; + // The index of the instruction in the source manager. + const unsigned Index; +}; - // Events generated by the Scheduler. +class HWInstructionIssuedEvent : public HWInstructionEvent { +public: using ResourceRef = std::pair; - virtual void - onInstructionIssued(unsigned Index, - const llvm::ArrayRef> &Used) {} - virtual void onInstructionExecuted(unsigned Index) {} - virtual void onInstructionReady(unsigned Index) {} - virtual void onResourceAvailable(const ResourceRef &RRef) {}; + HWInstructionIssuedEvent(unsigned Index, llvm::ArrayRef> UsedResources) + : HWInstructionEvent(HWInstructionEvent::Issued, Index), UsedResources(UsedResources) {} - // Events generated by the Dispatch logic. - virtual void onInstructionDispatched(unsigned Index) {} + const llvm::ArrayRef> UsedResources; +}; - // Generic events generated by the Backend. +class HWEventListener { +public: + // Generic events generated by the simulator. virtual void onCycleBegin(unsigned Cycle) {} virtual void onCycleEnd(unsigned Cycle) {} - virtual ~HWEventListener() = default; + virtual void onInstructionEvent(const HWInstructionEvent& Event) {} + + using ResourceRef = std::pair; + virtual void onResourceAvailable(const ResourceRef &RRef) {} + + virtual ~HWEventListener() {} + +private: virtual void anchor(); }; Index: tools/llvm-mca/ResourcePressureView.h =================================================================== --- tools/llvm-mca/ResourcePressureView.h +++ tools/llvm-mca/ResourcePressureView.h @@ -58,8 +58,8 @@ #ifndef LLVM_TOOLS_LLVM_MCA_RESOURCEPRESSUREVIEW_H #define LLVM_TOOLS_LLVM_MCA_RESOURCEPRESSUREVIEW_H -#include "SourceMgr.h" #include "View.h" +#include "SourceMgr.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCSubtargetInfo.h" #include @@ -97,9 +97,7 @@ initialize(ProcResourceMasks); } - void onInstructionIssued( - unsigned Index, - const llvm::ArrayRef> &Used) override; + void onInstructionEvent(const HWInstructionEvent& Event) override; void printView(llvm::raw_ostream &OS) const override { unsigned Executions = Source.getNumIterations(); Index: tools/llvm-mca/ResourcePressureView.cpp =================================================================== --- tools/llvm-mca/ResourcePressureView.cpp +++ tools/llvm-mca/ResourcePressureView.cpp @@ -42,10 +42,15 @@ std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0); } -void ResourcePressureView::onInstructionIssued( - unsigned Index, const ArrayRef> &Used) { - unsigned SourceIdx = Index % Source.size(); - for (const std::pair &Use : Used) { +void ResourcePressureView::onInstructionEvent( + const HWInstructionEvent& Event) { + // We're only interested in Issue events. + if (Event.Type != HWInstructionEvent::Issued) { + return; + } + const auto& IssueEvent = static_cast(Event); + unsigned SourceIdx = Event.Index % Source.size(); + for (const std::pair &Use : IssueEvent.UsedResources) { const ResourceRef &RR = Use.first; assert(Resource2VecIndex.find(RR.first) != Resource2VecIndex.end()); unsigned R2VIndex = Resource2VecIndex[RR.first]; Index: tools/llvm-mca/Scheduler.h =================================================================== --- tools/llvm-mca/Scheduler.h +++ tools/llvm-mca/Scheduler.h @@ -24,6 +24,8 @@ namespace mca { class Backend; +class DispatchUnit; + /// Used to notify the internal state of a processor resource. /// /// A processor resource is available if it is not reserved, and there are @@ -450,7 +452,10 @@ std::unique_ptr LSU; // The Backend gets notified when instructions are ready/issued/executed. - Backend *Owner; + Backend *const Owner; + + // The dispatch unit gets notified when instructions are executed. + DispatchUnit *DU; using QueueEntryTy = std::pair; std::map WaitQueue; @@ -481,6 +486,8 @@ AssumeNoAlias)), Owner(B) {} + void setDispatchUnit(DispatchUnit* DU) { this->DU = DU; } + /// Scheduling events. /// /// The DispatchUnit is responsible for querying the Scheduler before Index: tools/llvm-mca/Scheduler.cpp =================================================================== --- tools/llvm-mca/Scheduler.cpp +++ tools/llvm-mca/Scheduler.cpp @@ -13,6 +13,7 @@ #include "Scheduler.h" #include "Backend.h" +#include "HWEventListener.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -441,16 +442,29 @@ void Scheduler::notifyInstructionIssued( unsigned Index, const ArrayRef> &Used) { - Owner->notifyInstructionIssued(Index, Used); + DEBUG( + dbgs() << "[E] Instruction Issued: " << Index << '\n'; + for (const std::pair &Resource : Used) { + dbgs() << "[E] Resource Used: [" << Resource.first.first << '.' + << Resource.first.second << "]\n"; + dbgs() << " cycles: " << Resource.second << '\n'; + } + ); + Owner->notifyInstructionEvent(HWInstructionIssuedEvent(Index, Used)); } void Scheduler::notifyInstructionExecuted(unsigned Index) { LSU->onInstructionExecuted(Index); - Owner->notifyInstructionExecuted(Index); + DEBUG(dbgs() << "[E] Instruction Executed: " << Index << '\n'); + Owner->notifyInstructionEvent(HWInstructionEvent(HWInstructionEvent::Executed, Index)); + + const Instruction &IS = Owner->getInstruction(Index); + DU->onInstructionExecuted(IS.getRCUTokenID()); } void Scheduler::notifyInstructionReady(unsigned Index) { - Owner->notifyInstructionReady(Index); + DEBUG(dbgs() << "[E] Instruction Ready: " << Index << '\n'); + Owner->notifyInstructionEvent(HWInstructionEvent(HWInstructionEvent::Ready, Index)); } void Scheduler::notifyResourceAvailable(const ResourceRef &RR) { Index: tools/llvm-mca/TimelineView.h =================================================================== --- tools/llvm-mca/TimelineView.h +++ tools/llvm-mca/TimelineView.h @@ -100,8 +100,8 @@ #ifndef LLVM_TOOLS_LLVM_MCA_TIMELINEVIEW_H #define LLVM_TOOLS_LLVM_MCA_TIMELINEVIEW_H -#include "SourceMgr.h" #include "View.h" +#include "SourceMgr.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/raw_ostream.h" @@ -162,14 +162,8 @@ void initialize(unsigned MaxIterations); // Event handlers. - void onInstructionDispatched(unsigned Index) override; - void onInstructionReady(unsigned Index) override; - void onInstructionIssued( - unsigned Index, - const llvm::ArrayRef> &Used) override; - void onInstructionExecuted(unsigned Index) override; - void onInstructionRetired(unsigned Index) override; void onCycleBegin(unsigned Cycle) override { CurrentCycle = Cycle; } + void onInstructionEvent(const HWInstructionEvent& Event) override; // print functionalities. void printTimeline(llvm::raw_ostream &OS) const; Index: tools/llvm-mca/TimelineView.cpp =================================================================== --- tools/llvm-mca/TimelineView.cpp +++ tools/llvm-mca/TimelineView.cpp @@ -34,53 +34,44 @@ std::fill(WaitTime.begin(), WaitTime.end(), NullWTEntry); } -void TimelineView::onInstructionDispatched(unsigned Index) { - if (CurrentCycle >= MaxCycle || Index >= Timeline.size()) +void TimelineView::onInstructionEvent(const HWInstructionEvent& Event) { + if (CurrentCycle >= MaxCycle || Event.Index >= Timeline.size()) return; - Timeline[Index].CycleDispatched = CurrentCycle; - LastCycle = std::max(LastCycle, CurrentCycle); -} - -void TimelineView::onInstructionReady(unsigned Index) { - if (CurrentCycle >= MaxCycle || Index >= Timeline.size()) - return; - Timeline[Index].CycleReady = CurrentCycle; - LastCycle = std::max(LastCycle, CurrentCycle); -} - -void TimelineView::onInstructionIssued( - unsigned Index, - const ArrayRef> & /* Unused */) { - if (CurrentCycle >= MaxCycle || Index >= Timeline.size()) - return; - Timeline[Index].CycleIssued = CurrentCycle; - LastCycle = std::max(LastCycle, CurrentCycle); -} - -void TimelineView::onInstructionExecuted(unsigned Index) { - if (CurrentCycle >= MaxCycle || Index >= Timeline.size()) - return; - Timeline[Index].CycleExecuted = CurrentCycle; - LastCycle = std::max(LastCycle, CurrentCycle); -} - -void TimelineView::onInstructionRetired(unsigned Index) { - if (CurrentCycle >= MaxCycle || Index >= Timeline.size()) - return; - TimelineViewEntry &TVEntry = Timeline[Index]; - TVEntry.CycleRetired = CurrentCycle; - LastCycle = std::max(LastCycle, CurrentCycle); - - // Update the WaitTime entry which corresponds to this Index. - - WaitTimeEntry &WTEntry = WaitTime[Index % AsmSequence.size()]; - WTEntry.Executions++; - WTEntry.CyclesSpentInSchedulerQueue += - TVEntry.CycleIssued - TVEntry.CycleDispatched; - assert(TVEntry.CycleDispatched <= TVEntry.CycleReady); - WTEntry.CyclesSpentInSQWhileReady += TVEntry.CycleIssued - TVEntry.CycleReady; - WTEntry.CyclesSpentAfterWBAndBeforeRetire += + switch (Event.Type) { + case HWInstructionEvent::Retired: { + TimelineViewEntry &TVEntry = Timeline[Event.Index]; + TVEntry.CycleRetired = CurrentCycle; + LastCycle = std::max(LastCycle, CurrentCycle); + + // Update the WaitTime entry which corresponds to this Index. + + WaitTimeEntry &WTEntry = WaitTime[Event.Index % AsmSequence.size()]; + WTEntry.Executions++; + WTEntry.CyclesSpentInSchedulerQueue += + TVEntry.CycleIssued - TVEntry.CycleDispatched; + assert(TVEntry.CycleDispatched <= TVEntry.CycleReady); + WTEntry.CyclesSpentInSQWhileReady += + TVEntry.CycleIssued - TVEntry.CycleReady; + WTEntry.CyclesSpentAfterWBAndBeforeRetire += (TVEntry.CycleRetired - 1) - TVEntry.CycleExecuted; + break; + } + case HWInstructionEvent::Ready: + Timeline[Event.Index].CycleReady = CurrentCycle; + break; + case HWInstructionEvent::Issued: + Timeline[Event.Index].CycleIssued = CurrentCycle; + break; + case HWInstructionEvent::Executed: + Timeline[Event.Index].CycleExecuted = CurrentCycle; + break; + case HWInstructionEvent::Dispatched: + Timeline[Event.Index].CycleDispatched = CurrentCycle; + break; + default: + return; + } + LastCycle = std::max(LastCycle, CurrentCycle); } void TimelineView::printWaitTimeEntry(raw_string_ostream &OS, @@ -175,16 +166,14 @@ if (Entry.CycleDispatched != Entry.CycleExecuted) { // Zero latency instructions have the same value for CycleDispatched, // CycleIssued and CycleExecuted. - for (unsigned I = Entry.CycleDispatched + 1, E = Entry.CycleIssued; I < E; - ++I) + for (unsigned I = Entry.CycleDispatched + 1, E = Entry.CycleIssued; I < E; ++I) OS << '='; if (Entry.CycleIssued == Entry.CycleExecuted) OS << 'E'; else { if (Entry.CycleDispatched != Entry.CycleIssued) OS << 'e'; - for (unsigned I = Entry.CycleIssued + 1, E = Entry.CycleExecuted; I < E; - ++I) + for (unsigned I = Entry.CycleIssued + 1, E = Entry.CycleExecuted; I < E; ++I) OS << 'e'; OS << 'E'; }