Index: tools/llvm-mca/Views/ResourcePressureView.h =================================================================== --- tools/llvm-mca/Views/ResourcePressureView.h +++ tools/llvm-mca/Views/ResourcePressureView.h @@ -79,7 +79,7 @@ llvm::DenseMap Resource2VecIndex; // Table of resources used by instructions. - std::vector ResourceUsage; + std::vector ResourceUsage; unsigned NumResourceUnits; const llvm::MCInst &GetMCInstFromIndex(unsigned Index) const; Index: tools/llvm-mca/Views/ResourcePressureView.cpp =================================================================== --- tools/llvm-mca/Views/ResourcePressureView.cpp +++ tools/llvm-mca/Views/ResourcePressureView.cpp @@ -46,7 +46,8 @@ return; const auto &IssueEvent = static_cast(Event); const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size(); - for (const std::pair &Use : IssueEvent.UsedResources) { + 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/include/HWEventListener.h =================================================================== --- tools/llvm-mca/include/HWEventListener.h +++ tools/llvm-mca/include/HWEventListener.h @@ -17,7 +17,6 @@ #include "Instruction.h" #include "llvm/ADT/ArrayRef.h" -#include namespace mca { @@ -58,14 +57,56 @@ const InstRef &IR; }; +// This is a helper class to separate two values that are later used to produce +// the 'cycles per unit' ratio. We maintain these two quantities separately to +// reduce floating point error (we only produce the rational value when +// requested). 'Cycles' represents the number of clock cycles over some number +// of resource 'Units'. +class ResourceCycles { + unsigned Numerator, Denominator; // Cycles, ResourceUnits respectively. + +public: + ResourceCycles() : Numerator(0), Denominator(1) {} + ResourceCycles(unsigned Cycles, unsigned ResourceUnits = 1) + : Numerator(Cycles), Denominator(ResourceUnits) {} + + operator double() const { + assert(Denominator && "Invalid denominator (must be non-zero)."); + return (Denominator == 1) ? Numerator : (double)Numerator / Denominator; + } + + // Add the components of RHS to this instance. Instead of calculating + // the final value here, we keep track of the numerator and denominator + // separately, to reduce floating point error. + ResourceCycles &operator+=(const ResourceCycles &RHS) { + if (Denominator == RHS.Denominator) + Numerator += RHS.Numerator; + else { + // Create a common denominator for LHS and RHS by calculating the least + // common multiple from the GCD. + unsigned GCD = + llvm::GreatestCommonDivisor64(Denominator, RHS.Denominator); + unsigned LCM = (Denominator * RHS.Denominator) / GCD; + unsigned LHSNumerator = Numerator * (LCM / Denominator); + unsigned RHSNumerator = RHS.Numerator * (LCM / RHS.Denominator); + Numerator = LHSNumerator + RHSNumerator; + Denominator = LCM; + } + return *this; + } + + ResourceCycles operator+(const ResourceCycles &RHS) { return *this += RHS; } +}; + class HWInstructionIssuedEvent : public HWInstructionEvent { public: using ResourceRef = std::pair; - HWInstructionIssuedEvent(const InstRef &IR, - llvm::ArrayRef> UR) + HWInstructionIssuedEvent( + const InstRef &IR, + llvm::ArrayRef> UR) : HWInstructionEvent(HWInstructionEvent::Issued, IR), UsedResources(UR) {} - llvm::ArrayRef> UsedResources; + llvm::ArrayRef> UsedResources; }; class HWInstructionDispatchedEvent : public HWInstructionEvent { Index: tools/llvm-mca/include/HardwareUnits/ResourceManager.h =================================================================== --- tools/llvm-mca/include/HardwareUnits/ResourceManager.h +++ tools/llvm-mca/include/HardwareUnits/ResourceManager.h @@ -16,6 +16,7 @@ #ifndef LLVM_TOOLS_LLVM_MCA_RESOURCE_MANAGER_H #define LLVM_TOOLS_LLVM_MCA_RESOURCE_MANAGER_H +#include "HWEventListener.h" #include "Instruction.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -344,7 +345,7 @@ void issueInstruction( const InstrDesc &Desc, - llvm::SmallVectorImpl> &Pipes); + llvm::SmallVectorImpl> &Pipes); void cycleEvent(llvm::SmallVectorImpl &ResourcesFreed); Index: tools/llvm-mca/include/HardwareUnits/Scheduler.h =================================================================== --- tools/llvm-mca/include/HardwareUnits/Scheduler.h +++ tools/llvm-mca/include/HardwareUnits/Scheduler.h @@ -15,6 +15,7 @@ #ifndef LLVM_TOOLS_LLVM_MCA_SCHEDULER_H #define LLVM_TOOLS_LLVM_MCA_SCHEDULER_H +#include "HWEventListener.h" #include "HardwareUnits/HardwareUnit.h" #include "HardwareUnits/LSUnit.h" #include "ResourceManager.h" @@ -103,7 +104,7 @@ /// Issue an instruction without updating the ready queue. void issueInstructionImpl( InstRef &IR, - llvm::SmallVectorImpl> &Pipes); + llvm::SmallVectorImpl> &Pipes); // Identify instructions that have finished executing, and remove them from // the IssuedSet. References to executed instructions are added to input @@ -164,10 +165,10 @@ /// Issue an instruction and populates a vector of used pipeline resources, /// and a vector of instructions that transitioned to the ready state as a /// result of this event. - void - issueInstruction(InstRef &IR, - llvm::SmallVectorImpl> &Used, - llvm::SmallVectorImpl &Ready); + void issueInstruction( + InstRef &IR, + llvm::SmallVectorImpl> &Used, + llvm::SmallVectorImpl &Ready); /// Returns true if IR has to be issued immediately, or if IR is a zero /// latency instruction. Index: tools/llvm-mca/include/Stages/ExecuteStage.h =================================================================== --- tools/llvm-mca/include/Stages/ExecuteStage.h +++ tools/llvm-mca/include/Stages/ExecuteStage.h @@ -59,9 +59,9 @@ llvm::Error cycleStart() override; llvm::Error execute(InstRef &IR) override; - void - notifyInstructionIssued(const InstRef &IR, - llvm::ArrayRef> Used); + void notifyInstructionIssued( + const InstRef &IR, + llvm::ArrayRef> Used); void notifyInstructionExecuted(const InstRef &IR); void notifyInstructionReady(const InstRef &IR); void notifyResourceAvailable(const ResourceRef &RR); Index: tools/llvm-mca/include/Stages/InstructionTables.h =================================================================== --- tools/llvm-mca/include/Stages/InstructionTables.h +++ tools/llvm-mca/include/Stages/InstructionTables.h @@ -28,7 +28,7 @@ class InstructionTables final : public Stage { const llvm::MCSchedModel &SM; InstrBuilder &IB; - llvm::SmallVector, 4> UsedResources; + llvm::SmallVector, 4> UsedResources; public: InstructionTables(const llvm::MCSchedModel &Model, InstrBuilder &Builder) Index: tools/llvm-mca/lib/HardwareUnits/ResourceManager.cpp =================================================================== --- tools/llvm-mca/lib/HardwareUnits/ResourceManager.cpp +++ tools/llvm-mca/lib/HardwareUnits/ResourceManager.cpp @@ -247,7 +247,7 @@ void ResourceManager::issueInstruction( const InstrDesc &Desc, - SmallVectorImpl> &Pipes) { + SmallVectorImpl> &Pipes) { for (const std::pair &R : Desc.Resources) { const CycleSegment &CS = R.second.CS; if (!CS.size()) { @@ -263,8 +263,8 @@ // Replace the resource mask with a valid processor resource index. const ResourceState &RS = *Resources[getResourceStateIndex(Pipe.first)]; Pipe.first = RS.getProcResourceID(); - Pipes.emplace_back( - std::pair(Pipe, static_cast(CS.size()))); + Pipes.emplace_back(std::pair( + Pipe, ResourceCycles(CS.size()))); } else { assert((countPopulation(R.first) > 1) && "Expected a group!"); // Mark this group as reserved. Index: tools/llvm-mca/lib/HardwareUnits/Scheduler.cpp =================================================================== --- tools/llvm-mca/lib/HardwareUnits/Scheduler.cpp +++ tools/llvm-mca/lib/HardwareUnits/Scheduler.cpp @@ -66,7 +66,7 @@ void Scheduler::issueInstructionImpl( InstRef &IR, - SmallVectorImpl> &UsedResources) { + SmallVectorImpl> &UsedResources) { Instruction *IS = IR.getInstruction(); const InstrDesc &D = IS->getDesc(); @@ -86,7 +86,8 @@ // Release the buffered resources and issue the instruction. void Scheduler::issueInstruction( - InstRef &IR, SmallVectorImpl> &UsedResources, + InstRef &IR, + SmallVectorImpl> &UsedResources, SmallVectorImpl &ReadyInstructions) { const Instruction &Inst = *IR.getInstruction(); bool HasDependentUsers = Inst.hasDependentUsers(); Index: tools/llvm-mca/lib/Stages/ExecuteStage.cpp =================================================================== --- tools/llvm-mca/lib/Stages/ExecuteStage.cpp +++ tools/llvm-mca/lib/Stages/ExecuteStage.cpp @@ -53,11 +53,11 @@ } Error ExecuteStage::issueInstruction(InstRef &IR) { - SmallVector, 4> Used; + SmallVector, 4> Used; SmallVector Ready; HWS.issueInstruction(IR, Used, Ready); - notifyReservedOrReleasedBuffers(IR, /* Reserved */false); + notifyReservedOrReleasedBuffers(IR, /* Reserved */ false); notifyInstructionIssued(IR, Used); if (IR.getInstruction()->isExecuted()) { notifyInstructionExecuted(IR); @@ -120,7 +120,7 @@ // be released after MCIS is issued, and all the ResourceCycles for those // units have been consumed. HWS.dispatch(IR); - notifyReservedOrReleasedBuffers(IR, /* Reserved */true); + notifyReservedOrReleasedBuffers(IR, /* Reserved */ true); if (!HWS.isReady(IR)) return ErrorSuccess(); @@ -156,10 +156,10 @@ } void ExecuteStage::notifyInstructionIssued( - const InstRef &IR, ArrayRef> Used) { + const InstRef &IR, ArrayRef> Used) { LLVM_DEBUG({ dbgs() << "[E] Instruction Issued: #" << IR << '\n'; - for (const std::pair &Resource : Used) { + for (const std::pair &Resource : Used) { dbgs() << "[E] Resource Used: [" << Resource.first.first << '.' << Resource.first.second << "], "; dbgs() << "cycles: " << Resource.second << '\n'; Index: tools/llvm-mca/lib/Stages/InstructionTables.cpp =================================================================== --- tools/llvm-mca/lib/Stages/InstructionTables.cpp +++ tools/llvm-mca/lib/Stages/InstructionTables.cpp @@ -31,17 +31,17 @@ // Skip zero-cycle resources (i.e., unused resources). if (!Resource.second.size()) continue; - double Cycles = static_cast(Resource.second.size()); + unsigned Cycles = Resource.second.size(); unsigned Index = std::distance( Masks.begin(), std::find(Masks.begin(), Masks.end(), Resource.first)); const MCProcResourceDesc &ProcResource = *SM.getProcResource(Index); unsigned NumUnits = ProcResource.NumUnits; if (!ProcResource.SubUnitsIdxBegin) { // The number of cycles consumed by each unit. - Cycles /= NumUnits; for (unsigned I = 0, E = NumUnits; I < E; ++I) { ResourceRef ResourceUnit = std::make_pair(Index, 1U << I); - UsedResources.emplace_back(std::make_pair(ResourceUnit, Cycles)); + UsedResources.emplace_back( + std::make_pair(ResourceUnit, ResourceCycles(Cycles, NumUnits))); } continue; } @@ -53,10 +53,10 @@ unsigned SubUnitIdx = ProcResource.SubUnitsIdxBegin[I1]; const MCProcResourceDesc &SubUnit = *SM.getProcResource(SubUnitIdx); // Compute the number of cycles consumed by each resource unit. - double RUCycles = Cycles / (NumUnits * SubUnit.NumUnits); for (unsigned I2 = 0, E2 = SubUnit.NumUnits; I2 < E2; ++I2) { ResourceRef ResourceUnit = std::make_pair(SubUnitIdx, 1U << I2); - UsedResources.emplace_back(std::make_pair(ResourceUnit, RUCycles)); + UsedResources.emplace_back(std::make_pair( + ResourceUnit, ResourceCycles(Cycles, NumUnits * SubUnit.NumUnits))); } } }