diff options
-rw-r--r-- | llvm/tools/llvm-mca/Scheduler.cpp | 31 | ||||
-rw-r--r-- | llvm/tools/llvm-mca/Scheduler.h | 148 |
2 files changed, 98 insertions, 81 deletions
diff --git a/llvm/tools/llvm-mca/Scheduler.cpp b/llvm/tools/llvm-mca/Scheduler.cpp index 6e4d29b3715..49f037e99dc 100644 --- a/llvm/tools/llvm-mca/Scheduler.cpp +++ b/llvm/tools/llvm-mca/Scheduler.cpp @@ -22,6 +22,34 @@ using namespace llvm; #define DEBUG_TYPE "llvm-mca" +ResourceState::ResourceState(const llvm::MCProcResourceDesc &Desc, + unsigned Index, uint64_t Mask) + : ProcResourceDescIndex(Index), ResourceMask(Mask) { + if (llvm::countPopulation(ResourceMask) > 1) + ResourceSizeMask = ResourceMask ^ llvm::PowerOf2Floor(ResourceMask); + else + ResourceSizeMask = (1ULL << Desc.NumUnits) - 1; + NextInSequenceMask = ResourceSizeMask; + RemovedFromNextInSequence = 0; + ReadyMask = ResourceSizeMask; + BufferSize = Desc.BufferSize; + AvailableSlots = BufferSize == -1 ? 0U : static_cast<unsigned>(BufferSize); + Unavailable = false; +} + +bool ResourceState::isReady(unsigned NumUnits) const { + return (!isReserved() || isADispatchHazard()) && + llvm::countPopulation(ReadyMask) >= NumUnits; +} + +ResourceStateEvent ResourceState::isBufferAvailable() const { + if (isADispatchHazard() && isReserved()) + return RS_RESERVED; + if (!isBuffered() || AvailableSlots) + return RS_BUFFER_AVAILABLE; + return RS_BUFFER_UNAVAILABLE; +} + uint64_t ResourceState::selectNextInSequence() { assert(isReady()); uint64_t Next = getNextInSequence(); @@ -308,8 +336,7 @@ void Scheduler::issueInstructionImpl( // Release the buffered resources and issue the instruction. void Scheduler::issueInstruction( - InstRef &IR, - SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources, + InstRef &IR, SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources, SmallVectorImpl<InstRef> &ReadyInstructions) { const Instruction &Inst = *IR.getInstruction(); bool HasDependentUsers = Inst.hasDependentUsers(); diff --git a/llvm/tools/llvm-mca/Scheduler.h b/llvm/tools/llvm-mca/Scheduler.h index 3ac0b95e66a..abbc73fd25e 100644 --- a/llvm/tools/llvm-mca/Scheduler.h +++ b/llvm/tools/llvm-mca/Scheduler.h @@ -46,31 +46,27 @@ enum ResourceStateEvent { RS_RESERVED }; -/// A descriptor for processor resources. +/// A processor resource descriptor. /// -/// Each object of class ResourceState is associated to a specific processor -/// resource. There is an instance of this class for every processor resource -/// defined by the scheduling model. -/// A ResourceState dynamically tracks the availability of units of a processor -/// resource. For example, the ResourceState of a ProcResGroup tracks the -/// availability of resource units which are part of the group. -/// -/// Internally, ResourceState uses a round-robin selector to identify -/// which unit of the group shall be used next. +/// There is an instance of this class for every processor resource defined by +/// the machine scheduling model. +/// Objects of class ResourceState dynamically track the usage of processor +/// resource units. class ResourceState { - // Index to the MCProcResourceDesc in the processor Model. + /// An index to the MCProcResourceDesc entry in the processor model. unsigned ProcResourceDescIndex; - // A resource mask. This is generated by the tool with the help of - // function `mca::createProcResourceMasks' (see Support.h). + /// A resource mask. This is generated by the tool with the help of + /// function `mca::createProcResourceMasks' (see Support.h). uint64_t ResourceMask; - // A ProcResource can specify a number of units. For the purpose of dynamic - // scheduling, a processor resource with more than one unit behaves like a - // group. This field has one bit set for every unit/resource that is part of - // the group. - // For groups, this field defaults to 'ResourceMask'. For non-group - // resources, the number of bits set in this mask is equivalent to the - // number of units (i.e. field 'NumUnits' in 'ProcResourceUnits'). + /// A ProcResource can have multiple units. + /// + /// For processor resource groups, + /// this field default to the value of field `ResourceMask`; the number of + /// bits set is equal to the cardinality of the group. For normal (i.e. + /// non-group) resources, the number of bits set in this mask is equivalent + /// to the number of units declared by the processor model (see field + /// 'NumUnits' in 'ProcResourceUnits'). uint64_t ResourceSizeMask; // A simple round-robin selector for processor resources. @@ -89,10 +85,9 @@ class ResourceState { // // NextInSequenceMask -- 0b111 // - // Field NextInSequenceMask is used by the resource manager (i.e. - // an object of class ResourceManager) to select the "next available resource" - // from the set. The algorithm would prioritize resources with a bigger - // ResourceMask value. + // Field NextInSequenceMask is used by class ResourceManager to select the + // "next available resource" from the set. The algorithm would prioritizes + // resources with a bigger ResourceMask value. // // In this example, there are three resources in the set, and 'ResourceC' // has the highest mask value. The round-robin selector would firstly select @@ -121,30 +116,39 @@ class ResourceState { // removes any bits which are set in RemoveFromNextInSequence. uint64_t RemovedFromNextInSequence; - // A mask of ready units. + /// A mask of ready units. uint64_t ReadyMask; - // Buffered resources will have this field set to a positive number bigger - // than 0. A buffered resource behaves like a separate reservation station - // implementing its own buffer for out-of-order execution. - // A buffer of 1 is for units that force in-order execution. - // A value of 0 is treated specially. In particular, a resource with - // A BufferSize = 0 is for an in-order issue/dispatch resource. - // That means, this resource is reserved starting from the dispatch event, - // until all the "resource cycles" are consumed after the issue event. - // While this resource is reserved, no other instruction may be dispatched. + /// Buffered resources will have this field set to a positive number different + /// than zero. A buffered resource behaves like a reservation station + /// implementing its own buffer for out-of-order execution. + /// + /// A BufferSize of 1 is used by scheduler resources that force in-order + /// execution. + /// + /// A BufferSize of 0 is used to model in-order issue/dispatch resources. + /// Since in-order issue/dispatch resources don't implement buffers, dispatch + /// events coincide with issue events. + /// Also, no other instruction ca be dispatched/issue while this resource is + /// in use. Only when all the "resource cycles" are consumed (after the issue + /// event), a new instruction ca be dispatched. int BufferSize; - // Available slots in the buffer (zero, if this is not a buffered resource). + /// Available slots in the buffer (zero, if this is not a buffered resource). unsigned AvailableSlots; - // True if this is resource is currently unavailable. - // An instruction may "reserve" a resource for a number of cycles. - // During those cycles, the reserved resource cannot be used for other - // instructions, even if the ReadyMask is set. + /// This field is set if this resource is currently reserved. + /// + /// Resources can be reserved for a number of cycles. + /// Instructions can still be dispatched to reserved resources. However, + /// istructions dispatched to a reserved resource cannot be issued to the + /// underlying units (i.e. pipelines) until the resource is released. bool Unavailable; - bool isSubResourceReady(uint64_t ID) const { return ReadyMask & ID; } + /// Checks for the availability of unit 'SubResMask' in the group. + bool isSubResourceReady(uint64_t SubResMask) const { + return ReadyMask & SubResMask; + } /// Returns the mask identifier of the next available resource in the set. uint64_t getNextInSequence() const { @@ -160,25 +164,9 @@ class ResourceState { NextInSequenceMask = ResourceSizeMask; } - uint64_t computeResourceSizeMaskForGroup(uint64_t ResourceMask) { - assert(llvm::countPopulation(ResourceMask) > 1); - return ResourceMask ^ llvm::PowerOf2Floor(ResourceMask); - } - public: ResourceState(const llvm::MCProcResourceDesc &Desc, unsigned Index, - uint64_t Mask) - : ProcResourceDescIndex(Index), ResourceMask(Mask) { - bool IsAGroup = llvm::countPopulation(ResourceMask) > 1; - ResourceSizeMask = IsAGroup ? computeResourceSizeMaskForGroup(ResourceMask) - : ((1ULL << Desc.NumUnits) - 1); - NextInSequenceMask = ResourceSizeMask; - RemovedFromNextInSequence = 0; - ReadyMask = ResourceSizeMask; - BufferSize = Desc.BufferSize; - AvailableSlots = BufferSize == -1 ? 0U : static_cast<unsigned>(BufferSize); - Unavailable = false; - } + uint64_t Mask); unsigned getProcResourceID() const { return ProcResourceDescIndex; } uint64_t getResourceMask() const { return ResourceMask; } @@ -186,28 +174,25 @@ public: bool isBuffered() const { return BufferSize > 0; } bool isInOrder() const { return BufferSize == 1; } + + /// Returns true if this is an in-order dispatch/issue resource. bool isADispatchHazard() const { return BufferSize == 0; } bool isReserved() const { return Unavailable; } void setReserved() { Unavailable = true; } void clearReserved() { Unavailable = false; } - // A resource is ready if it is not reserved, and if there are enough - // available units. - // If a resource is also a dispatch hazard, then we don't check if - // it is reserved because that check would always return true. - // A resource marked as "dispatch hazard" is always reserved at - // dispatch time. When this method is called, the assumption is that - // the user of this resource has been already dispatched. - bool isReady(unsigned NumUnits = 1) const { - return (!isReserved() || isADispatchHazard()) && - llvm::countPopulation(ReadyMask) >= NumUnits; - } + /// Returs true if this resource is not reserved, and if there are at least + /// `NumUnits` available units. + bool isReady(unsigned NumUnits = 1) const; + bool isAResourceGroup() const { return llvm::countPopulation(ResourceMask) > 1; } - bool containsResource(uint64_t ID) const { return ResourceMask & ID; } + bool containsResource(uint64_t ID) const { + return ResourceMask & ID; + } void markSubResourceAsUsed(uint64_t ID) { assert(isSubResourceReady(ID)); @@ -226,19 +211,24 @@ public: uint64_t selectNextInSequence(); void removeFromNextInSequence(uint64_t ID); - ResourceStateEvent isBufferAvailable() const { - if (isADispatchHazard() && isReserved()) - return RS_RESERVED; - if (!isBuffered() || AvailableSlots) - return RS_BUFFER_AVAILABLE; - return RS_BUFFER_UNAVAILABLE; - } + /// Checks if there is an available slot in the resource buffer. + /// + /// Returns RS_BUFFER_AVAILABLE if this is not a buffered resource, or if + /// there is a slot available. + /// + /// Returns RS_RESERVED if this buffered resource is a dispatch hazard, and it + /// is reserved. + /// + /// Returns RS_BUFFER_UNAVAILABLE if there are no available slots. + ResourceStateEvent isBufferAvailable() const; + /// Reserve a slot in the buffer. void reserveBuffer() { if (AvailableSlots) AvailableSlots--; } + /// Release a slot in the buffer. void releaseBuffer() { if (BufferSize > 0) AvailableSlots++; @@ -427,8 +417,7 @@ class Scheduler : public HardwareUnit { public: Scheduler(const llvm::MCSchedModel &Model, LSUnit *Lsu) - : LSU(Lsu), - Strategy(llvm::make_unique<DefaultSchedulerStrategy>()), + : LSU(Lsu), Strategy(llvm::make_unique<DefaultSchedulerStrategy>()), Resources(llvm::make_unique<ResourceManager>(Model)) {} Scheduler(const llvm::MCSchedModel &Model, LSUnit *Lsu, std::unique_ptr<SchedulerStrategy> SelectStrategy) @@ -473,7 +462,8 @@ public: /// 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, + void + issueInstruction(InstRef &IR, llvm::SmallVectorImpl<std::pair<ResourceRef, double>> &Used, llvm::SmallVectorImpl<InstRef> &Ready); |