blob: f1cfcbe6b2b0570eecec1693e439419b955dadae [file] [log] [blame]
Andrew Walbran16937d02019-10-22 13:54:20 +01001//===--------------------- Scheduler.h ------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8/// \file
9///
10/// A scheduler for Processor Resource Units and Processor Resource Groups.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_MCA_SCHEDULER_H
15#define LLVM_MCA_SCHEDULER_H
16
17#include "llvm/ADT/SmallVector.h"
18#include "llvm/MC/MCSchedule.h"
19#include "llvm/MCA/HardwareUnits/HardwareUnit.h"
20#include "llvm/MCA/HardwareUnits/LSUnit.h"
21#include "llvm/MCA/HardwareUnits/ResourceManager.h"
22#include "llvm/MCA/Support.h"
23
24namespace llvm {
25namespace mca {
26
27class SchedulerStrategy {
28public:
29 SchedulerStrategy() = default;
30 virtual ~SchedulerStrategy();
31
32 /// Returns true if Lhs should take priority over Rhs.
33 ///
34 /// This method is used by class Scheduler to select the "best" ready
35 /// instruction to issue to the underlying pipelines.
36 virtual bool compare(const InstRef &Lhs, const InstRef &Rhs) const = 0;
37};
38
39/// Default instruction selection strategy used by class Scheduler.
40class DefaultSchedulerStrategy : public SchedulerStrategy {
41 /// This method ranks instructions based on their age, and the number of known
42 /// users. The lower the rank value, the better.
43 int computeRank(const InstRef &Lhs) const {
44 return Lhs.getSourceIndex() - Lhs.getInstruction()->getNumUsers();
45 }
46
47public:
48 DefaultSchedulerStrategy() = default;
49 virtual ~DefaultSchedulerStrategy();
50
51 bool compare(const InstRef &Lhs, const InstRef &Rhs) const override {
52 int LhsRank = computeRank(Lhs);
53 int RhsRank = computeRank(Rhs);
54
55 /// Prioritize older instructions over younger instructions to minimize the
56 /// pressure on the reorder buffer.
57 if (LhsRank == RhsRank)
58 return Lhs.getSourceIndex() < Rhs.getSourceIndex();
59 return LhsRank < RhsRank;
60 }
61};
62
63/// Class Scheduler is responsible for issuing instructions to pipeline
64/// resources.
65///
66/// Internally, it delegates to a ResourceManager the management of processor
67/// resources. This class is also responsible for tracking the progress of
68/// instructions from the dispatch stage, until the write-back stage.
69///
70class Scheduler : public HardwareUnit {
71 LSUnit &LSU;
72
73 // Instruction selection strategy for this Scheduler.
74 std::unique_ptr<SchedulerStrategy> Strategy;
75
76 // Hardware resources that are managed by this scheduler.
77 std::unique_ptr<ResourceManager> Resources;
78
79 // Instructions dispatched to the Scheduler are internally classified based on
80 // the instruction stage (see Instruction::InstrStage).
81 //
82 // An Instruction dispatched to the Scheduler is added to the WaitSet if not
83 // all its register operands are available, and at least one latency is unknown.
84 // By construction, the WaitSet only contains instructions that are in the
85 // IS_DISPATCHED stage.
86 //
87 // An Instruction transitions from the WaitSet to the PendingSet if the
88 // instruction is not ready yet, but the latency of every register read is known.
89 // Instructions in the PendingSet are expected to be in the IS_PENDING stage.
90 //
91 // Instructions in the PendingSet are immediately dominated only by
92 // instructions that have already been issued to the underlying pipelines.
93 // In the presence of bottlenecks caused by data dependencies, the PendingSet
94 // can be inspected to identify problematic data dependencies between
95 // instructions.
96 //
97 // An instruction is moved to the ReadySet when all register operands become
98 // available, and all memory dependencies are met. Instructions that are
99 // moved from the PendingSet to the ReadySet transition in state from
100 // 'IS_PENDING' to 'IS_READY'.
101 //
102 // On every cycle, the Scheduler checks if it can promote instructions from the
103 // PendingSet to the ReadySet.
104 //
105 // An Instruction is moved from the ReadySet to the `IssuedSet` when it starts
106 // exection. This event also causes an instruction state transition (i.e. from
107 // state IS_READY, to state IS_EXECUTING). An Instruction leaves the IssuedSet
108 // only when it reaches the write-back stage.
109 std::vector<InstRef> WaitSet;
110 std::vector<InstRef> PendingSet;
111 std::vector<InstRef> ReadySet;
112 std::vector<InstRef> IssuedSet;
113
114 // A mask of busy resource units. It defaults to the empty set (i.e. a zero
115 // mask), and it is cleared at the beginning of every cycle.
116 // It is updated every time the scheduler fails to issue an instruction from
117 // the ready set due to unavailable pipeline resources.
118 // Each bit of the mask represents an unavailable resource.
119 uint64_t BusyResourceUnits;
120
121 /// Verify the given selection strategy and set the Strategy member
122 /// accordingly. If no strategy is provided, the DefaultSchedulerStrategy is
123 /// used.
124 void initializeStrategy(std::unique_ptr<SchedulerStrategy> S);
125
126 /// Issue an instruction without updating the ready queue.
127 void issueInstructionImpl(
128 InstRef &IR,
129 SmallVectorImpl<std::pair<ResourceRef, ResourceCycles>> &Pipes);
130
131 // Identify instructions that have finished executing, and remove them from
132 // the IssuedSet. References to executed instructions are added to input
133 // vector 'Executed'.
134 void updateIssuedSet(SmallVectorImpl<InstRef> &Executed);
135
136 // Try to promote instructions from the PendingSet to the ReadySet.
137 // Add promoted instructions to the 'Ready' vector in input.
138 // Returns true if at least one instruction was promoted.
139 bool promoteToReadySet(SmallVectorImpl<InstRef> &Ready);
140
141 // Try to promote instructions from the WaitSet to the PendingSet.
142 // Returns true if at least one instruction was promoted.
143 bool promoteToPendingSet();
144
145public:
146 Scheduler(const MCSchedModel &Model, LSUnit &Lsu)
147 : Scheduler(Model, Lsu, nullptr) {}
148
149 Scheduler(const MCSchedModel &Model, LSUnit &Lsu,
150 std::unique_ptr<SchedulerStrategy> SelectStrategy)
151 : Scheduler(make_unique<ResourceManager>(Model), Lsu,
152 std::move(SelectStrategy)) {}
153
154 Scheduler(std::unique_ptr<ResourceManager> RM, LSUnit &Lsu,
155 std::unique_ptr<SchedulerStrategy> SelectStrategy)
156 : LSU(Lsu), Resources(std::move(RM)), BusyResourceUnits(0) {
157 initializeStrategy(std::move(SelectStrategy));
158 }
159
160 // Stalls generated by the scheduler.
161 enum Status {
162 SC_AVAILABLE,
163 SC_LOAD_QUEUE_FULL,
164 SC_STORE_QUEUE_FULL,
165 SC_BUFFERS_FULL,
166 SC_DISPATCH_GROUP_STALL,
167 };
168
169 /// Check if the instruction in 'IR' can be dispatched and returns an answer
170 /// in the form of a Status value.
171 ///
172 /// The DispatchStage is responsible for querying the Scheduler before
173 /// dispatching new instructions. This routine is used for performing such
174 /// a query. If the instruction 'IR' can be dispatched, then true is
175 /// returned, otherwise false is returned with Event set to the stall type.
176 /// Internally, it also checks if the load/store unit is available.
177 Status isAvailable(const InstRef &IR) const;
178
179 /// Reserves buffer and LSUnit queue resources that are necessary to issue
180 /// this instruction.
181 ///
182 /// Returns true if instruction IR is ready to be issued to the underlying
183 /// pipelines. Note that this operation cannot fail; it assumes that a
184 /// previous call to method `isAvailable(IR)` returned `SC_AVAILABLE`.
185 void dispatch(const InstRef &IR);
186
187 /// Returns true if IR is ready to be executed by the underlying pipelines.
188 /// This method assumes that IR has been previously dispatched.
189 bool isReady(const InstRef &IR) const;
190
191 /// Issue an instruction and populates a vector of used pipeline resources,
192 /// and a vector of instructions that transitioned to the ready state as a
193 /// result of this event.
194 void issueInstruction(
195 InstRef &IR,
196 SmallVectorImpl<std::pair<ResourceRef, ResourceCycles>> &Used,
197 SmallVectorImpl<InstRef> &Ready);
198
199 /// Returns true if IR has to be issued immediately, or if IR is a zero
200 /// latency instruction.
201 bool mustIssueImmediately(const InstRef &IR) const;
202
203 /// This routine notifies the Scheduler that a new cycle just started.
204 ///
205 /// It notifies the underlying ResourceManager that a new cycle just started.
206 /// Vector `Freed` is populated with resourceRef related to resources that
207 /// have changed in state, and that are now available to new instructions.
208 /// Instructions executed are added to vector Executed, while vector Ready is
209 /// populated with instructions that have become ready in this new cycle.
210 void cycleEvent(SmallVectorImpl<ResourceRef> &Freed,
211 SmallVectorImpl<InstRef> &Ready,
212 SmallVectorImpl<InstRef> &Executed);
213
214 /// Convert a resource mask into a valid llvm processor resource identifier.
215 unsigned getResourceID(uint64_t Mask) const {
216 return Resources->resolveResourceMask(Mask);
217 }
218
219 /// Select the next instruction to issue from the ReadySet. Returns an invalid
220 /// instruction reference if there are no ready instructions, or if processor
221 /// resources are not available.
222 InstRef select();
223
224 /// Returns a mask of busy resources. Each bit of the mask identifies a unique
225 /// processor resource unit. In the absence of bottlenecks caused by resource
226 /// pressure, the mask value returned by this method is always zero.
227 uint64_t getBusyResourceUnits() const { return BusyResourceUnits; }
228 bool arePipelinesFullyUsed() const {
229 return !Resources->getAvailableProcResUnits();
230 }
231 bool isReadySetEmpty() const { return ReadySet.empty(); }
232 bool isWaitSetEmpty() const { return WaitSet.empty(); }
233
234#ifndef NDEBUG
235 // Update the ready queues.
236 void dump() const;
237
238 // This routine performs a sanity check. This routine should only be called
239 // when we know that 'IR' is not in the scheduler's instruction queues.
240 void sanityCheck(const InstRef &IR) const {
241 assert(find(WaitSet, IR) == WaitSet.end() && "Already in the wait set!");
242 assert(find(ReadySet, IR) == ReadySet.end() && "Already in the ready set!");
243 assert(find(IssuedSet, IR) == IssuedSet.end() && "Already executing!");
244 }
245#endif // !NDEBUG
246};
247} // namespace mca
248} // namespace llvm
249
250#endif // LLVM_MCA_SCHEDULER_H