Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 1 | //===--------------------- Scheduler.h ------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | /// \file |
| 10 | /// |
| 11 | /// A scheduler for Processor Resource Units and Processor Resource Groups. |
| 12 | /// |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #ifndef LLVM_TOOLS_LLVM_MCA_SCHEDULER_H |
| 16 | #define LLVM_TOOLS_LLVM_MCA_SCHEDULER_H |
| 17 | |
Matt Davis | 271ce76 | 2018-08-27 17:16:32 +0000 | [diff] [blame^] | 18 | #include "HardwareUnits/HardwareUnit.h" |
| 19 | #include "HardwareUnits/LSUnit.h" |
Matt Davis | 673412e | 2018-08-24 22:59:13 +0000 | [diff] [blame] | 20 | #include "ResourceManager.h" |
Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 21 | #include "llvm/ADT/SmallVector.h" |
Matt Davis | 673412e | 2018-08-24 22:59:13 +0000 | [diff] [blame] | 22 | #include "llvm/MC/MCSchedule.h" |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 23 | |
| 24 | namespace mca { |
| 25 | |
Andrea Di Biagio | f3374f0 | 2018-08-21 18:20:16 +0000 | [diff] [blame] | 26 | class SchedulerStrategy { |
| 27 | public: |
| 28 | SchedulerStrategy() = default; |
| 29 | virtual ~SchedulerStrategy(); |
| 30 | |
| 31 | /// Returns true if Lhs should take priority over Rhs. |
| 32 | /// |
| 33 | /// This method is used by class Scheduler to select the "best" ready |
| 34 | /// instruction to issue to the underlying pipelines. |
| 35 | virtual bool compare(const InstRef &Lhs, const InstRef &Rhs) const = 0; |
| 36 | }; |
| 37 | |
| 38 | /// Default instruction selection strategy used by class Scheduler. |
| 39 | class DefaultSchedulerStrategy : public SchedulerStrategy { |
| 40 | /// This method ranks instructions based on their age, and the number of known |
| 41 | /// users. The lower the rank value, the better. |
| 42 | int computeRank(const InstRef &Lhs) const { |
| 43 | return Lhs.getSourceIndex() - Lhs.getInstruction()->getNumUsers(); |
| 44 | } |
| 45 | |
| 46 | public: |
| 47 | DefaultSchedulerStrategy() = default; |
| 48 | virtual ~DefaultSchedulerStrategy(); |
| 49 | |
| 50 | bool compare(const InstRef &Lhs, const InstRef &Rhs) const override { |
| 51 | int LhsRank = computeRank(Lhs); |
| 52 | int RhsRank = computeRank(Rhs); |
| 53 | |
| 54 | /// Prioritize older instructions over younger instructions to minimize the |
| 55 | /// pressure on the reorder buffer. |
| 56 | if (LhsRank == RhsRank) |
| 57 | return Lhs.getSourceIndex() < Rhs.getSourceIndex(); |
| 58 | return LhsRank < RhsRank; |
| 59 | } |
| 60 | }; |
| 61 | |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 62 | /// Class Scheduler is responsible for issuing instructions to pipeline |
Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 63 | /// resources. |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 64 | /// |
Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 65 | /// Internally, it delegates to a ResourceManager the management of processor |
| 66 | /// resources. This class is also responsible for tracking the progress of |
| 67 | /// instructions from the dispatch stage, until the write-back stage. |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 68 | /// |
Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 69 | /// An instruction dispatched to the Scheduler is initially placed into either |
| 70 | /// the 'WaitSet' or the 'ReadySet' depending on the availability of the input |
| 71 | /// operands. |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 72 | /// |
Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 73 | /// An instruction is moved from the WaitSet to the ReadySet when register |
| 74 | /// operands become available, and all memory dependencies are met. |
| 75 | /// Instructions that are moved from the WaitSet to the ReadySet transition |
| 76 | /// in state from 'IS_AVAILABLE' to 'IS_READY'. |
| 77 | /// |
| 78 | /// On every cycle, the Scheduler checks if it can promote instructions from the |
| 79 | /// WaitSet to the ReadySet. |
| 80 | /// |
| 81 | /// An Instruction is moved from the ReadySet the `IssuedSet` when it is issued |
| 82 | /// to a (one or more) pipeline(s). This event also causes an instruction state |
| 83 | /// transition (i.e. from state IS_READY, to state IS_EXECUTING). An Instruction |
| 84 | /// leaves the IssuedSet when it reaches the write-back stage. |
Matt Davis | 362ea5f | 2018-07-06 18:03:14 +0000 | [diff] [blame] | 85 | class Scheduler : public HardwareUnit { |
Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 86 | LSUnit *LSU; |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 87 | |
Andrea Di Biagio | f3374f0 | 2018-08-21 18:20:16 +0000 | [diff] [blame] | 88 | // Instruction selection strategy for this Scheduler. |
| 89 | std::unique_ptr<SchedulerStrategy> Strategy; |
| 90 | |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 91 | // Hardware resources that are managed by this scheduler. |
| 92 | std::unique_ptr<ResourceManager> Resources; |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 93 | |
Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 94 | std::vector<InstRef> WaitSet; |
| 95 | std::vector<InstRef> ReadySet; |
| 96 | std::vector<InstRef> IssuedSet; |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 97 | |
Matt Davis | 0f70bc0 | 2018-08-23 18:42:37 +0000 | [diff] [blame] | 98 | /// Verify the given selection strategy and set the Strategy member |
| 99 | /// accordingly. If no strategy is provided, the DefaultSchedulerStrategy is |
| 100 | /// used. |
| 101 | void initializeStrategy(std::unique_ptr<SchedulerStrategy> S); |
| 102 | |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 103 | /// Issue an instruction without updating the ready queue. |
Andrea Di Biagio | 27c4b09 | 2018-04-24 14:53:16 +0000 | [diff] [blame] | 104 | void issueInstructionImpl( |
Matt Davis | 21a8d32 | 2018-05-07 18:29:15 +0000 | [diff] [blame] | 105 | InstRef &IR, |
Andrea Di Biagio | 27c4b09 | 2018-04-24 14:53:16 +0000 | [diff] [blame] | 106 | llvm::SmallVectorImpl<std::pair<ResourceRef, double>> &Pipes); |
| 107 | |
Andrea Di Biagio | 5184995 | 2018-08-21 12:40:15 +0000 | [diff] [blame] | 108 | // Identify instructions that have finished executing, and remove them from |
| 109 | // the IssuedSet. References to executed instructions are added to input |
| 110 | // vector 'Executed'. |
| 111 | void updateIssuedSet(llvm::SmallVectorImpl<InstRef> &Executed); |
| 112 | |
| 113 | // Try to promote instructions from WaitSet to ReadySet. |
| 114 | // Add promoted instructions to the 'Ready' vector in input. |
| 115 | void promoteToReadySet(llvm::SmallVectorImpl<InstRef> &Ready); |
| 116 | |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 117 | public: |
Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 118 | Scheduler(const llvm::MCSchedModel &Model, LSUnit *Lsu) |
Matt Davis | 0f70bc0 | 2018-08-23 18:42:37 +0000 | [diff] [blame] | 119 | : LSU(Lsu), Resources(llvm::make_unique<ResourceManager>(Model)) { |
| 120 | initializeStrategy(nullptr); |
| 121 | } |
Andrea Di Biagio | f3374f0 | 2018-08-21 18:20:16 +0000 | [diff] [blame] | 122 | Scheduler(const llvm::MCSchedModel &Model, LSUnit *Lsu, |
| 123 | std::unique_ptr<SchedulerStrategy> SelectStrategy) |
Matt Davis | 0f70bc0 | 2018-08-23 18:42:37 +0000 | [diff] [blame] | 124 | : LSU(Lsu), Resources(llvm::make_unique<ResourceManager>(Model)) { |
| 125 | initializeStrategy(std::move(SelectStrategy)); |
| 126 | } |
Andrea Di Biagio | f3374f0 | 2018-08-21 18:20:16 +0000 | [diff] [blame] | 127 | Scheduler(std::unique_ptr<ResourceManager> RM, LSUnit *Lsu, |
| 128 | std::unique_ptr<SchedulerStrategy> SelectStrategy) |
Matt Davis | 0f70bc0 | 2018-08-23 18:42:37 +0000 | [diff] [blame] | 129 | : LSU(Lsu), Resources(std::move(RM)) { |
| 130 | initializeStrategy(std::move(SelectStrategy)); |
| 131 | } |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 132 | |
Andrea Di Biagio | 163419f | 2018-08-17 15:01:37 +0000 | [diff] [blame] | 133 | // Stalls generated by the scheduler. |
Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 134 | enum Status { |
| 135 | SC_AVAILABLE, |
| 136 | SC_LOAD_QUEUE_FULL, |
| 137 | SC_STORE_QUEUE_FULL, |
| 138 | SC_BUFFERS_FULL, |
| 139 | SC_DISPATCH_GROUP_STALL, |
Andrea Di Biagio | 163419f | 2018-08-17 15:01:37 +0000 | [diff] [blame] | 140 | }; |
| 141 | |
Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 142 | /// Check if the instruction in 'IR' can be dispatched and returns an answer |
| 143 | /// in the form of a Status value. |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 144 | /// |
Matt Davis | 679083e | 2018-05-17 19:22:29 +0000 | [diff] [blame] | 145 | /// The DispatchStage is responsible for querying the Scheduler before |
Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 146 | /// dispatching new instructions. This routine is used for performing such |
| 147 | /// a query. If the instruction 'IR' can be dispatched, then true is |
| 148 | /// returned, otherwise false is returned with Event set to the stall type. |
Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 149 | /// Internally, it also checks if the load/store unit is available. |
| 150 | Status isAvailable(const InstRef &IR) const; |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 151 | |
Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 152 | /// Reserves buffer and LSUnit queue resources that are necessary to issue |
| 153 | /// this instruction. |
| 154 | /// |
| 155 | /// Returns true if instruction IR is ready to be issued to the underlying |
| 156 | /// pipelines. Note that this operation cannot fail; it assumes that a |
| 157 | /// previous call to method `isAvailable(IR)` returned `SC_AVAILABLE`. |
| 158 | void dispatch(const InstRef &IR); |
| 159 | |
| 160 | /// Returns true if IR is ready to be executed by the underlying pipelines. |
| 161 | /// This method assumes that IR has been previously dispatched. |
| 162 | bool isReady(const InstRef &IR) const; |
Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 163 | |
Andrea Di Biagio | 5184995 | 2018-08-21 12:40:15 +0000 | [diff] [blame] | 164 | /// Issue an instruction and populates a vector of used pipeline resources, |
| 165 | /// and a vector of instructions that transitioned to the ready state as a |
| 166 | /// result of this event. |
Andrea Di Biagio | 4660fd2 | 2018-08-22 10:23:28 +0000 | [diff] [blame] | 167 | void |
| 168 | issueInstruction(InstRef &IR, |
Andrea Di Biagio | 5184995 | 2018-08-21 12:40:15 +0000 | [diff] [blame] | 169 | llvm::SmallVectorImpl<std::pair<ResourceRef, double>> &Used, |
| 170 | llvm::SmallVectorImpl<InstRef> &Ready); |
Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 171 | |
Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 172 | /// Returns true if IR has to be issued immediately, or if IR is a zero |
| 173 | /// latency instruction. |
| 174 | bool mustIssueImmediately(const InstRef &IR) const; |
Andrea Di Biagio | 27c4b09 | 2018-04-24 14:53:16 +0000 | [diff] [blame] | 175 | |
Andrea Di Biagio | 5184995 | 2018-08-21 12:40:15 +0000 | [diff] [blame] | 176 | /// This routine notifies the Scheduler that a new cycle just started. |
| 177 | /// |
| 178 | /// It notifies the underlying ResourceManager that a new cycle just started. |
| 179 | /// Vector `Freed` is populated with resourceRef related to resources that |
| 180 | /// have changed in state, and that are now available to new instructions. |
| 181 | /// Instructions executed are added to vector Executed, while vector Ready is |
| 182 | /// populated with instructions that have become ready in this new cycle. |
| 183 | void cycleEvent(llvm::SmallVectorImpl<ResourceRef> &Freed, |
| 184 | llvm::SmallVectorImpl<InstRef> &Ready, |
| 185 | llvm::SmallVectorImpl<InstRef> &Executed); |
Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 186 | |
Andrea Di Biagio | 5184995 | 2018-08-21 12:40:15 +0000 | [diff] [blame] | 187 | /// Convert a resource mask into a valid llvm processor resource identifier. |
| 188 | unsigned getResourceID(uint64_t Mask) const { |
Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 189 | return Resources->resolveResourceMask(Mask); |
| 190 | } |
| 191 | |
Andrea Di Biagio | f3374f0 | 2018-08-21 18:20:16 +0000 | [diff] [blame] | 192 | /// Select the next instruction to issue from the ReadySet. Returns an invalid |
| 193 | /// instruction reference if there are no ready instructions, or if processor |
| 194 | /// resources are not available. |
Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 195 | InstRef select(); |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 196 | |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 197 | #ifndef NDEBUG |
Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 198 | // Update the ready queues. |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 199 | void dump() const; |
Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 200 | |
Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 201 | // This routine performs a sanity check. This routine should only be called |
| 202 | // when we know that 'IR' is not in the scheduler's instruction queues. |
| 203 | void sanityCheck(const InstRef &IR) const { |
Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 204 | assert(llvm::find(WaitSet, IR) == WaitSet.end()); |
| 205 | assert(llvm::find(ReadySet, IR) == ReadySet.end()); |
| 206 | assert(llvm::find(IssuedSet, IR) == IssuedSet.end()); |
Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 207 | } |
| 208 | #endif // !NDEBUG |
| 209 | }; |
| 210 | } // namespace mca |
| 211 | |
| 212 | #endif // LLVM_TOOLS_LLVM_MCA_SCHEDULER_H |