LLVM 23.0.0git
ResourceManager.h
Go to the documentation of this file.
1//===--------------------- ResourceManager.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/// The classes here represent processor resource units and their management
11/// strategy. These classes are managed by the Scheduler.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_MCA_HARDWAREUNITS_RESOURCEMANAGER_H
16#define LLVM_MCA_HARDWAREUNITS_RESOURCEMANAGER_H
17
18#include "llvm/ADT/DenseMap.h"
20#include "llvm/MC/MCSchedule.h"
22#include "llvm/MCA/Support.h"
24
25namespace llvm {
26namespace mca {
27
28/// Used to notify the internal state of a processor resource.
29///
30/// A processor resource is available if it is not reserved, and there are
31/// available slots in the buffer. A processor resource is unavailable if it
32/// is either reserved, or the associated buffer is full. A processor resource
33/// with a buffer size of -1 is always available if it is not reserved.
34///
35/// Values of type ResourceStateEvent are returned by method
36/// ResourceManager::canBeDispatched()
37///
38/// The naming convention for resource state events is:
39/// * Event names start with prefix RS_
40/// * Prefix RS_ is followed by a string describing the actual resource state.
46
47/// Resource allocation strategy used by hardware scheduler resources.
48class LLVM_ABI ResourceStrategy {
49 ResourceStrategy(const ResourceStrategy &) = delete;
50 ResourceStrategy &operator=(const ResourceStrategy &) = delete;
51
52public:
53 ResourceStrategy() = default;
55
56 /// Selects a processor resource unit from a ReadyMask.
57 virtual uint64_t select(uint64_t ReadyMask) = 0;
58
59 /// Called by the ResourceManager when a processor resource group, or a
60 /// processor resource with multiple units has become unavailable.
61 ///
62 /// The default strategy uses this information to bias its selection logic.
63 virtual void used(uint64_t ResourceMask) {}
64};
65
66/// Default resource allocation strategy used by processor resource groups and
67/// processor resources with multiple units.
68class LLVM_ABI DefaultResourceStrategy final : public ResourceStrategy {
69 /// A Mask of resource unit identifiers.
70 ///
71 /// There is one bit set for every available resource unit.
72 /// It defaults to the value of field ResourceSizeMask in ResourceState.
73 const uint64_t ResourceUnitMask;
74
75 /// A simple round-robin selector for processor resource units.
76 /// Each bit of this mask identifies a sub resource within a group.
77 ///
78 /// As an example, lets assume that this is a default policy for a
79 /// processor resource group composed by the following three units:
80 /// ResourceA -- 0b001
81 /// ResourceB -- 0b010
82 /// ResourceC -- 0b100
83 ///
84 /// Field NextInSequenceMask is used to select the next unit from the set of
85 /// resource units. It defaults to the value of field `ResourceUnitMasks` (in
86 /// this example, it defaults to mask '0b111').
87 ///
88 /// The round-robin selector would firstly select 'ResourceC', then
89 /// 'ResourceB', and eventually 'ResourceA'. When a resource R is used, the
90 /// corresponding bit in NextInSequenceMask is cleared. For example, if
91 /// 'ResourceC' is selected, then the new value of NextInSequenceMask becomes
92 /// 0xb011.
93 ///
94 /// When NextInSequenceMask becomes zero, it is automatically reset to the
95 /// default value (i.e. ResourceUnitMask).
96 uint64_t NextInSequenceMask;
97
98 /// This field is used to track resource units that are used (i.e. selected)
99 /// by other groups other than the one associated with this strategy object.
100 ///
101 /// In LLVM processor resource groups are allowed to partially (or fully)
102 /// overlap. That means, a same unit may be visible to multiple groups.
103 /// This field keeps track of uses that have originated from outside of
104 /// this group. The idea is to bias the selection strategy, so that resources
105 /// that haven't been used by other groups get prioritized.
106 ///
107 /// The end goal is to (try to) keep the resource distribution as much uniform
108 /// as possible. By construction, this mask only tracks one-level of resource
109 /// usage. Therefore, this strategy is expected to be less accurate when same
110 /// units are used multiple times by other groups within a single round of
111 /// select.
112 ///
113 /// Note: an LRU selector would have a better accuracy at the cost of being
114 /// slightly more expensive (mostly in terms of runtime cost). Methods
115 /// 'select' and 'used', are always in the hot execution path of llvm-mca.
116 /// Therefore, a slow implementation of 'select' would have a negative impact
117 /// on the overall performance of the tool.
118 uint64_t RemovedFromNextInSequence;
119
120public:
122 : ResourceUnitMask(UnitMask), NextInSequenceMask(UnitMask),
123 RemovedFromNextInSequence(0) {}
124 ~DefaultResourceStrategy() override = default;
125
126 uint64_t select(uint64_t ReadyMask) override;
127 void used(uint64_t Mask) override;
128};
129
130/// A processor resource descriptor.
131///
132/// There is an instance of this class for every processor resource defined by
133/// the machine scheduling model.
134/// Objects of class ResourceState dynamically track the usage of processor
135/// resource units.
137 /// An index to the MCProcResourceDesc entry in the processor model.
138 const unsigned ProcResourceDescIndex;
139
140 /// A resource mask. This is generated by the tool with the help of
141 /// function `mca::computeProcResourceMasks' (see Support.h).
142 ///
143 /// Field ResourceMask only has one bit set if this resource state describes a
144 /// processor resource unit (i.e. this is not a group). That means, we can
145 /// quickly check if a resource is a group by simply counting the number of
146 /// bits that are set in the mask.
147 ///
148 /// The most significant bit of a mask (MSB) uniquely identifies a resource.
149 /// Remaining bits are used to describe the composition of a group (Group).
150 ///
151 /// Example (little endian):
152 /// Resource | Mask | MSB | Group
153 /// ---------+------------+------------+------------
154 /// A | 0b000001 | 0b000001 | 0b000000
155 /// | | |
156 /// B | 0b000010 | 0b000010 | 0b000000
157 /// | | |
158 /// C | 0b010000 | 0b010000 | 0b000000
159 /// | | |
160 /// D | 0b110010 | 0b100000 | 0b010010
161 ///
162 /// In this example, resources A, B and C are processor resource units.
163 /// Only resource D is a group resource, and it contains resources B and C.
164 /// That is because MSB(B) and MSB(C) are both contained within Group(D).
165 const uint64_t ResourceMask;
166
167 /// This field is set iff this resource is a group resource. This class can
168 /// represent either a processor resource unit or a processor resource group
169 /// composition.
170 const bool IsAGroup;
171
172 /// A ProcResource can have multiple units.
173 ///
174 /// For processor resource groups this field is a mask of contained resource
175 /// units. It is obtained from ResourceMask by clearing the highest set bit.
176 /// The number of resource units in a group can be simply computed as the
177 /// population count of this field.
178 ///
179 /// For normal (i.e. non-group) resources, the number of bits set in this mask
180 /// is equivalent to the number of units declared by the processor model (see
181 /// field 'NumUnits' in 'ProcResourceUnits').
182 const uint64_t ResourceSizeMask;
183
184 /// A mask of ready units.
185 uint64_t ReadyMask;
186
187 /// Buffered resources will have this field set to a positive number different
188 /// than zero. A buffered resource behaves like a reservation station
189 /// implementing its own buffer for out-of-order execution.
190 ///
191 /// A BufferSize of 1 is used by scheduler resources that force in-order
192 /// execution.
193 ///
194 /// A BufferSize of 0 is used to model in-order issue/dispatch resources.
195 /// Since in-order issue/dispatch resources don't implement buffers, dispatch
196 /// events coincide with issue events.
197 /// Also, no other instruction ca be dispatched/issue while this resource is
198 /// in use. Only when all the "resource cycles" are consumed (after the issue
199 /// event), a new instruction ca be dispatched.
200 const int BufferSize;
201
202 /// Available slots in the buffer (zero, if this is not a buffered resource).
203 unsigned AvailableSlots;
204
205 /// This field is set if this resource is currently reserved.
206 ///
207 /// Resources can be reserved for a number of cycles.
208 /// Instructions can still be dispatched to reserved resources. However,
209 /// istructions dispatched to a reserved resource cannot be issued to the
210 /// underlying units (i.e. pipelines) until the resource is released.
211 bool Unavailable;
212
213 /// Checks for the availability of unit 'SubResMask' in the group.
214 bool isSubResourceReady(uint64_t SubResMask) const {
215 return ReadyMask & SubResMask;
216 }
217
218public:
219 LLVM_ABI ResourceState(const MCProcResourceDesc &Desc, unsigned Index,
220 uint64_t Mask);
221
222 unsigned getProcResourceID() const { return ProcResourceDescIndex; }
223 uint64_t getResourceMask() const { return ResourceMask; }
224 uint64_t getReadyMask() const { return ReadyMask; }
225 int getBufferSize() const { return BufferSize; }
226
227 bool isBuffered() const { return BufferSize > 0; }
228 bool isInOrder() const { return BufferSize == 1; }
229
230 /// Returns true if this is an in-order dispatch/issue resource.
231 bool isADispatchHazard() const { return BufferSize == 0; }
232 bool isReserved() const { return Unavailable; }
233
234 void setReserved() { Unavailable = true; }
235 void clearReserved() { Unavailable = false; }
236
237 /// Returs true if this resource is not reserved, and if there are at least
238 /// `NumUnits` available units.
239 LLVM_ABI bool isReady(unsigned NumUnits = 1) const;
240
241 uint64_t getNumReadyUnits() const { return llvm::popcount(ReadyMask); }
242
243 bool isAResourceGroup() const { return IsAGroup; }
244
245 bool containsResource(uint64_t ID) const { return ResourceMask & ID; }
246
247 void markSubResourceAsUsed(uint64_t ID) {
248 assert(isSubResourceReady(ID));
249 ReadyMask ^= ID;
250 }
251
252 void releaseSubResource(uint64_t ID) {
253 assert(!isSubResourceReady(ID));
254 ReadyMask ^= ID;
255 }
256
257 unsigned getNumUnits() const {
258 return isAResourceGroup() ? 1U : llvm::popcount(ResourceSizeMask);
259 }
260
261 /// Checks if there is an available slot in the resource buffer.
262 ///
263 /// Returns RS_BUFFER_AVAILABLE if this is not a buffered resource, or if
264 /// there is a slot available.
265 ///
266 /// Returns RS_RESERVED if this buffered resource is a dispatch hazard, and it
267 /// is reserved.
268 ///
269 /// Returns RS_BUFFER_UNAVAILABLE if there are no available slots.
270 LLVM_ABI ResourceStateEvent isBufferAvailable() const;
271
272 /// Reserve a buffer slot.
273 ///
274 /// Returns true if the buffer is not full.
275 /// It always returns true if BufferSize is set to zero.
276 bool reserveBuffer() {
277 if (BufferSize <= 0)
278 return true;
279
280 --AvailableSlots;
281 assert(AvailableSlots <= static_cast<unsigned>(BufferSize));
282 return AvailableSlots;
283 }
284
285 /// Releases a slot in the buffer.
286 void releaseBuffer() {
287 // Ignore dispatch hazards or invalid buffer sizes.
288 if (BufferSize <= 0)
289 return;
290
291 ++AvailableSlots;
292 assert(AvailableSlots <= static_cast<unsigned>(BufferSize));
293 }
294
295#ifndef NDEBUG
296 void dump() const;
297#endif
298};
299
300/// A resource unit identifier.
301///
302/// This is used to identify a specific processor resource unit using a pair
303/// of indices where the 'first' index is a processor resource mask, and the
304/// 'second' index is an index for a "sub-resource" (i.e. unit).
305typedef std::pair<uint64_t, uint64_t> ResourceRef;
306
307// First: a MCProcResourceDesc index identifying a buffered resource.
308// Second: max number of buffer entries used in this resource.
309typedef std::pair<unsigned, unsigned> BufferUsageEntry;
310
311/// A resource manager for processor resource units and groups.
312///
313/// This class owns all the ResourceState objects, and it is responsible for
314/// acting on requests from a Scheduler by updating the internal state of
315/// ResourceState objects.
316/// This class doesn't know about instruction itineraries and functional units.
317/// In future, it can be extended to support itineraries too through the same
318/// public interface.
319class ResourceManager {
320 // Set of resources available on the subtarget.
321 //
322 // There is an instance of ResourceState for every resource declared by the
323 // target scheduling model.
324 //
325 // Elements of this vector are ordered by resource kind. In particular,
326 // resource units take precedence over resource groups.
327 //
328 // The index of a processor resource in this vector depends on the value of
329 // its mask (see the description of field ResourceState::ResourceMask). In
330 // particular, it is computed as the position of the most significant bit set
331 // (MSB) in the mask plus one (since we want to ignore the invalid resource
332 // descriptor at index zero).
333 //
334 // Example (little endian):
335 //
336 // Resource | Mask | MSB | Index
337 // ---------+---------+---------+-------
338 // A | 0b00001 | 0b00001 | 1
339 // | | |
340 // B | 0b00100 | 0b00100 | 3
341 // | | |
342 // C | 0b10010 | 0b10000 | 5
343 //
344 //
345 // The same index is also used to address elements within vector `Strategies`
346 // and vector `Resource2Groups`.
347 std::vector<std::unique_ptr<ResourceState>> Resources;
348 std::vector<std::unique_ptr<ResourceStrategy>> Strategies;
349
350 // Used to quickly identify groups that own a particular resource unit.
351 std::vector<uint64_t> Resource2Groups;
352
353 // A table that maps processor resource IDs to processor resource masks.
354 SmallVector<uint64_t, 8> ProcResID2Mask;
355
356 // A table that maps resource indices to actual processor resource IDs in the
357 // scheduling model.
358 SmallVector<unsigned, 8> ResIndex2ProcResID;
359
360 // Keeps track of which resources are busy, and how many cycles are left
361 // before those become usable again.
363
364 // Set of processor resource units available on the target.
365 uint64_t ProcResUnitMask;
366
367 // Set of processor resource units that are available during this cycle.
368 uint64_t AvailableProcResUnits;
369
370 // Set of processor resources that are currently reserved.
371 uint64_t ReservedResourceGroups;
372
373 // Set of unavailable scheduler buffer resources. This is used internally to
374 // speedup `canBeDispatched()` queries.
375 uint64_t AvailableBuffers;
376
377 // Set of dispatch hazard buffer resources that are currently unavailable.
378 uint64_t ReservedBuffers;
379
380 // Returns the actual resource unit that will be used.
381 ResourceRef selectPipe(uint64_t ResourceID);
382
383 void use(const ResourceRef &RR);
384 void release(const ResourceRef &RR);
385
386 unsigned getNumUnits(uint64_t ResourceID) const;
387
388 // Overrides the selection strategy for the processor resource with the given
389 // mask.
390 LLVM_ABI void setCustomStrategyImpl(std::unique_ptr<ResourceStrategy> S,
391 uint64_t ResourceMask);
392
393public:
395 virtual ~ResourceManager() = default;
396
397 // Overrides the selection strategy for the resource at index ResourceID in
398 // the MCProcResourceDesc table.
399 void setCustomStrategy(std::unique_ptr<ResourceStrategy> S,
400 unsigned ResourceID) {
401 assert(ResourceID < ProcResID2Mask.size() &&
402 "Invalid resource index in input!");
403 return setCustomStrategyImpl(std::move(S), ProcResID2Mask[ResourceID]);
404 }
405
406 // Returns RS_BUFFER_AVAILABLE if buffered resources are not reserved, and if
407 // there are enough available slots in the buffers.
408 LLVM_ABI ResourceStateEvent canBeDispatched(uint64_t ConsumedBuffers) const;
409
410 // Return the processor resource identifier associated to this Mask.
411 LLVM_ABI unsigned resolveResourceMask(uint64_t Mask) const;
412
413 // Acquires a slot from every buffered resource in mask `ConsumedBuffers`.
414 // Units that are dispatch hazards (i.e. BufferSize=0) are marked as reserved.
415 LLVM_ABI void reserveBuffers(uint64_t ConsumedBuffers);
416
417 // Releases a slot from every buffered resource in mask `ConsumedBuffers`.
418 // ConsumedBuffers is a bitmask of previously acquired buffers (using method
419 // `reserveBuffers`). Units that are dispatch hazards (i.e. BufferSize=0) are
420 // not automatically unreserved by this method.
421 LLVM_ABI void releaseBuffers(uint64_t ConsumedBuffers);
422
423 // Reserve a processor resource. A reserved resource is not available for
424 // instruction issue until it is released.
425 LLVM_ABI void reserveResource(uint64_t ResourceID);
426
427 // Release a previously reserved processor resource.
428 LLVM_ABI void releaseResource(uint64_t ResourceID);
429
430 // Returns a zero mask if resources requested by Desc are all available during
431 // this cycle. It returns a non-zero mask value only if there are unavailable
432 // processor resources; each bit set in the mask represents a busy processor
433 // resource unit or a reserved processor resource group.
434 LLVM_ABI uint64_t checkAvailability(const InstrDesc &Desc) const;
435
436 uint64_t getProcResUnitMask() const { return ProcResUnitMask; }
437 uint64_t getAvailableProcResUnits() const { return AvailableProcResUnits; }
438
439 using ResourceWithCycles = std::pair<ResourceRef, ReleaseAtCycles>;
440
441 void issueInstruction(const InstrDesc &Desc,
442 SmallVectorImpl<ResourceWithCycles> &Pipes) {
443 if (Desc.HasPartiallyOverlappingGroups)
444 return issueInstructionImpl(Desc, Pipes);
445
446 return fastIssueInstruction(Desc, Pipes);
447 }
448
449 // Selects pipeline resources consumed by an instruction.
450 // This method works under the assumption that used group resources don't
451 // partially overlap. The logic is guaranteed to find a valid resource unit
452 // schedule, no matter in which order individual uses are processed. For that
453 // reason, the vector of resource uses is simply (and quickly) processed in
454 // sequence. The resulting schedule is eventually stored into vector `Pipes`.
455 LLVM_ABI void
456 fastIssueInstruction(const InstrDesc &Desc,
457 SmallVectorImpl<ResourceWithCycles> &Pipes);
458
459 // Selects pipeline resources consumed by an instruction.
460 // This method works under the assumption that used resource groups may
461 // partially overlap. This complicates the selection process, because the
462 // order in which uses are processed matters. The logic internally prioritizes
463 // groups which are more constrained than others.
464 LLVM_ABI void
465 issueInstructionImpl(const InstrDesc &Desc,
466 SmallVectorImpl<ResourceWithCycles> &Pipes);
467
468 LLVM_ABI void cycleEvent(SmallVectorImpl<ResourceRef> &ResourcesFreed);
469
470#ifndef NDEBUG
471 void dump() const {
472 for (const std::unique_ptr<ResourceState> &Resource : Resources)
473 Resource->dump();
474 }
475#endif
476};
477} // namespace mca
478} // namespace llvm
479
480#endif // LLVM_MCA_HARDWAREUNITS_RESOURCEMANAGER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define LLVM_ABI
Definition Compiler.h:213
This file defines the DenseMap class.
@ Unavailable
We know the block is not fully available. This is a fixpoint.
Definition GVN.cpp:949
Move duplicate certain instructions close to their use
Definition Localizer.cpp:33
This file defines abstractions used by the Pipeline to model register reads, register writes and inst...
static constexpr unsigned SM(unsigned Version)
This file defines the SmallVector class.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
void used(uint64_t Mask) override
Called by the ResourceManager when a processor resource group, or a processor resource with multiple ...
~DefaultResourceStrategy() override=default
uint64_t select(uint64_t ReadyMask) override
Selects a processor resource unit from a ReadyMask.
A processor resource descriptor.
virtual uint64_t select(uint64_t ReadyMask)=0
Selects a processor resource unit from a ReadyMask.
virtual void used(uint64_t ResourceMask)
Called by the ResourceManager when a processor resource group, or a processor resource with multiple ...
Helper functions used by various pipeline components.
char InstructionError< T >::ID
Definition Support.h:44
ResourceStateEvent
Used to notify the internal state of a processor resource.
std::pair< uint64_t, uint64_t > ResourceRef
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
Op::Description Desc
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
Definition bit.h:154
Define a kind of processor resource that will be modeled by the scheduler.
Definition MCSchedule.h:36
Machine model for scheduling, bundling, and heuristics.
Definition MCSchedule.h:258