|
|
|||
File indexing completed on 2026-05-10 08:44:16
0001 //===--------------------- Scheduler.h ------------------------*- C++ -*-===// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 /// \file 0009 /// 0010 /// A scheduler for Processor Resource Units and Processor Resource Groups. 0011 /// 0012 //===----------------------------------------------------------------------===// 0013 0014 #ifndef LLVM_MCA_HARDWAREUNITS_SCHEDULER_H 0015 #define LLVM_MCA_HARDWAREUNITS_SCHEDULER_H 0016 0017 #include "llvm/ADT/SmallVector.h" 0018 #include "llvm/MC/MCSchedule.h" 0019 #include "llvm/MCA/HardwareUnits/HardwareUnit.h" 0020 #include "llvm/MCA/HardwareUnits/LSUnit.h" 0021 #include "llvm/MCA/HardwareUnits/ResourceManager.h" 0022 #include "llvm/MCA/Support.h" 0023 0024 namespace llvm { 0025 namespace mca { 0026 0027 class SchedulerStrategy { 0028 public: 0029 SchedulerStrategy() = default; 0030 virtual ~SchedulerStrategy(); 0031 0032 /// Returns true if Lhs should take priority over Rhs. 0033 /// 0034 /// This method is used by class Scheduler to select the "best" ready 0035 /// instruction to issue to the underlying pipelines. 0036 virtual bool compare(const InstRef &Lhs, const InstRef &Rhs) const = 0; 0037 }; 0038 0039 /// Default instruction selection strategy used by class Scheduler. 0040 class DefaultSchedulerStrategy : public SchedulerStrategy { 0041 /// This method ranks instructions based on their age, and the number of known 0042 /// users. The lower the rank value, the better. 0043 int computeRank(const InstRef &Lhs) const { 0044 return Lhs.getSourceIndex() - Lhs.getInstruction()->getNumUsers(); 0045 } 0046 0047 public: 0048 DefaultSchedulerStrategy() = default; 0049 virtual ~DefaultSchedulerStrategy(); 0050 0051 bool compare(const InstRef &Lhs, const InstRef &Rhs) const override { 0052 int LhsRank = computeRank(Lhs); 0053 int RhsRank = computeRank(Rhs); 0054 0055 /// Prioritize older instructions over younger instructions to minimize the 0056 /// pressure on the reorder buffer. 0057 if (LhsRank == RhsRank) 0058 return Lhs.getSourceIndex() < Rhs.getSourceIndex(); 0059 return LhsRank < RhsRank; 0060 } 0061 }; 0062 0063 /// Class Scheduler is responsible for issuing instructions to pipeline 0064 /// resources. 0065 /// 0066 /// Internally, it delegates to a ResourceManager the management of processor 0067 /// resources. This class is also responsible for tracking the progress of 0068 /// instructions from the dispatch stage, until the write-back stage. 0069 /// 0070 class Scheduler : public HardwareUnit { 0071 LSUnitBase &LSU; 0072 0073 // Instruction selection strategy for this Scheduler. 0074 std::unique_ptr<SchedulerStrategy> Strategy; 0075 0076 // Hardware resources that are managed by this scheduler. 0077 std::unique_ptr<ResourceManager> Resources; 0078 0079 // Instructions dispatched to the Scheduler are internally classified based on 0080 // the instruction stage (see Instruction::InstrStage). 0081 // 0082 // An Instruction dispatched to the Scheduler is added to the WaitSet if not 0083 // all its register operands are available, and at least one latency is 0084 // unknown. By construction, the WaitSet only contains instructions that are 0085 // in the IS_DISPATCHED stage. 0086 // 0087 // An Instruction transitions from the WaitSet to the PendingSet if the 0088 // instruction is not ready yet, but the latency of every register read is 0089 // known. Instructions in the PendingSet can only be in the IS_PENDING or 0090 // IS_READY stage. Only IS_READY instructions that are waiting on memory 0091 // dependencies can be added to the PendingSet. 0092 // 0093 // Instructions in the PendingSet are immediately dominated only by 0094 // instructions that have already been issued to the underlying pipelines. In 0095 // the presence of bottlenecks caused by data dependencies, the PendingSet can 0096 // be inspected to identify problematic data dependencies between 0097 // instructions. 0098 // 0099 // An instruction is moved to the ReadySet when all register operands become 0100 // available, and all memory dependencies are met. Instructions that are 0101 // moved from the PendingSet to the ReadySet must transition to the 'IS_READY' 0102 // stage. 0103 // 0104 // On every cycle, the Scheduler checks if it can promote instructions from the 0105 // PendingSet to the ReadySet. 0106 // 0107 // An Instruction is moved from the ReadySet to the `IssuedSet` when it starts 0108 // exection. This event also causes an instruction state transition (i.e. from 0109 // state IS_READY, to state IS_EXECUTING). An Instruction leaves the IssuedSet 0110 // only when it reaches the write-back stage. 0111 std::vector<InstRef> WaitSet; 0112 std::vector<InstRef> PendingSet; 0113 std::vector<InstRef> ReadySet; 0114 std::vector<InstRef> IssuedSet; 0115 0116 // A mask of busy resource units. It defaults to the empty set (i.e. a zero 0117 // mask), and it is cleared at the beginning of every cycle. 0118 // It is updated every time the scheduler fails to issue an instruction from 0119 // the ready set due to unavailable pipeline resources. 0120 // Each bit of the mask represents an unavailable resource. 0121 uint64_t BusyResourceUnits; 0122 0123 // Counts the number of instructions in the pending set that were dispatched 0124 // during this cycle. 0125 unsigned NumDispatchedToThePendingSet; 0126 0127 // True if the previous pipeline Stage was unable to dispatch a full group of 0128 // opcodes because scheduler buffers (or LS queues) were unavailable. 0129 bool HadTokenStall; 0130 0131 /// Verify the given selection strategy and set the Strategy member 0132 /// accordingly. If no strategy is provided, the DefaultSchedulerStrategy is 0133 /// used. 0134 void initializeStrategy(std::unique_ptr<SchedulerStrategy> S); 0135 0136 /// Issue an instruction without updating the ready queue. 0137 void issueInstructionImpl( 0138 InstRef &IR, 0139 SmallVectorImpl<std::pair<ResourceRef, ReleaseAtCycles>> &Pipes); 0140 0141 // Identify instructions that have finished executing, and remove them from 0142 // the IssuedSet. References to executed instructions are added to input 0143 // vector 'Executed'. 0144 void updateIssuedSet(SmallVectorImpl<InstRef> &Executed); 0145 0146 // Try to promote instructions from the PendingSet to the ReadySet. 0147 // Add promoted instructions to the 'Ready' vector in input. 0148 // Returns true if at least one instruction was promoted. 0149 bool promoteToReadySet(SmallVectorImpl<InstRef> &Ready); 0150 0151 // Try to promote instructions from the WaitSet to the PendingSet. 0152 // Add promoted instructions to the 'Pending' vector in input. 0153 // Returns true if at least one instruction was promoted. 0154 bool promoteToPendingSet(SmallVectorImpl<InstRef> &Pending); 0155 0156 public: 0157 Scheduler(const MCSchedModel &Model, LSUnitBase &Lsu) 0158 : Scheduler(Model, Lsu, nullptr) {} 0159 0160 Scheduler(const MCSchedModel &Model, LSUnitBase &Lsu, 0161 std::unique_ptr<SchedulerStrategy> SelectStrategy) 0162 : Scheduler(std::make_unique<ResourceManager>(Model), Lsu, 0163 std::move(SelectStrategy)) {} 0164 0165 Scheduler(std::unique_ptr<ResourceManager> RM, LSUnitBase &Lsu, 0166 std::unique_ptr<SchedulerStrategy> SelectStrategy) 0167 : LSU(Lsu), Resources(std::move(RM)), BusyResourceUnits(0), 0168 NumDispatchedToThePendingSet(0), HadTokenStall(false) { 0169 initializeStrategy(std::move(SelectStrategy)); 0170 } 0171 0172 // Stalls generated by the scheduler. 0173 enum Status { 0174 SC_AVAILABLE, 0175 SC_LOAD_QUEUE_FULL, 0176 SC_STORE_QUEUE_FULL, 0177 SC_BUFFERS_FULL, 0178 SC_DISPATCH_GROUP_STALL, 0179 }; 0180 0181 /// Check if the instruction in 'IR' can be dispatched during this cycle. 0182 /// Return SC_AVAILABLE if both scheduler and LS resources are available. 0183 /// 0184 /// This method is also responsible for setting field HadTokenStall if 0185 /// IR cannot be dispatched to the Scheduler due to unavailable resources. 0186 Status isAvailable(const InstRef &IR); 0187 0188 /// Reserves buffer and LSUnit queue resources that are necessary to issue 0189 /// this instruction. 0190 /// 0191 /// Returns true if instruction IR is ready to be issued to the underlying 0192 /// pipelines. Note that this operation cannot fail; it assumes that a 0193 /// previous call to method `isAvailable(IR)` returned `SC_AVAILABLE`. 0194 /// 0195 /// If IR is a memory operation, then the Scheduler queries the LS unit to 0196 /// obtain a LS token. An LS token is used internally to track memory 0197 /// dependencies. 0198 bool dispatch(InstRef &IR); 0199 0200 /// Issue an instruction and populates a vector of used pipeline resources, 0201 /// and a vector of instructions that transitioned to the ready state as a 0202 /// result of this event. 0203 void issueInstruction( 0204 InstRef &IR, 0205 SmallVectorImpl<std::pair<ResourceRef, ReleaseAtCycles>> &Used, 0206 SmallVectorImpl<InstRef> &Pending, 0207 SmallVectorImpl<InstRef> &Ready); 0208 0209 /// Returns true if IR has to be issued immediately, or if IR is a zero 0210 /// latency instruction. 0211 bool mustIssueImmediately(const InstRef &IR) const; 0212 0213 /// This routine notifies the Scheduler that a new cycle just started. 0214 /// 0215 /// It notifies the underlying ResourceManager that a new cycle just started. 0216 /// Vector `Freed` is populated with resourceRef related to resources that 0217 /// have changed in state, and that are now available to new instructions. 0218 /// Instructions executed are added to vector Executed, while vector Ready is 0219 /// populated with instructions that have become ready in this new cycle. 0220 /// Vector Pending is popluated by instructions that have transitioned through 0221 /// the pending stat during this cycle. The Pending and Ready sets may not be 0222 /// disjoint. An instruction is allowed to transition from the WAIT state to 0223 /// the READY state (going through the PENDING state) within a single cycle. 0224 /// That means, instructions may appear in both the Pending and Ready set. 0225 void cycleEvent(SmallVectorImpl<ResourceRef> &Freed, 0226 SmallVectorImpl<InstRef> &Executed, 0227 SmallVectorImpl<InstRef> &Pending, 0228 SmallVectorImpl<InstRef> &Ready); 0229 0230 /// Convert a resource mask into a valid llvm processor resource identifier. 0231 /// 0232 /// Only the most significant bit of the Mask is used by this method to 0233 /// identify the processor resource. 0234 unsigned getResourceID(uint64_t Mask) const { 0235 return Resources->resolveResourceMask(Mask); 0236 } 0237 0238 /// Select the next instruction to issue from the ReadySet. Returns an invalid 0239 /// instruction reference if there are no ready instructions, or if processor 0240 /// resources are not available. 0241 InstRef select(); 0242 0243 bool isReadySetEmpty() const { return ReadySet.empty(); } 0244 bool isWaitSetEmpty() const { return WaitSet.empty(); } 0245 0246 /// This method is called by the ExecuteStage at the end of each cycle to 0247 /// identify bottlenecks caused by data dependencies. Vector RegDeps is 0248 /// populated by instructions that were not issued because of unsolved 0249 /// register dependencies. Vector MemDeps is populated by instructions that 0250 /// were not issued because of unsolved memory dependencies. 0251 void analyzeDataDependencies(SmallVectorImpl<InstRef> &RegDeps, 0252 SmallVectorImpl<InstRef> &MemDeps); 0253 0254 /// Returns a mask of busy resources, and populates vector Insts with 0255 /// instructions that could not be issued to the underlying pipelines because 0256 /// not all pipeline resources were available. 0257 uint64_t analyzeResourcePressure(SmallVectorImpl<InstRef> &Insts); 0258 0259 // Returns true if the dispatch logic couldn't dispatch a full group due to 0260 // unavailable scheduler and/or LS resources. 0261 bool hadTokenStall() const { return HadTokenStall; } 0262 0263 #ifndef NDEBUG 0264 // Update the ready queues. 0265 void dump() const; 0266 0267 // This routine performs a basic correctness check. This routine should only 0268 // be called when we know that 'IR' is not in the scheduler's instruction 0269 // queues. 0270 void instructionCheck(const InstRef &IR) const { 0271 assert(!is_contained(WaitSet, IR) && "Already in the wait set!"); 0272 assert(!is_contained(ReadySet, IR) && "Already in the ready set!"); 0273 assert(!is_contained(IssuedSet, IR) && "Already executing!"); 0274 } 0275 #endif // !NDEBUG 0276 }; 0277 } // namespace mca 0278 } // namespace llvm 0279 0280 #endif // LLVM_MCA_HARDWAREUNITS_SCHEDULER_H
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|