LLVM 24.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, const MCSchedModel &SM,
221 float ReservationStationScaleFactor);
222
223 unsigned getProcResourceID() const { return ProcResourceDescIndex; }
224 uint64_t getResourceMask() const { return ResourceMask; }
225 uint64_t getReadyMask() const { return ReadyMask; }
226 int getBufferSize() const { return BufferSize; }
227
228 bool isBuffered() const { return BufferSize > 0; }
229 bool isInOrder() const { return BufferSize == 1; }
230
231 /// Returns true if this is an in-order dispatch/issue resource.
232 bool isADispatchHazard() const { return BufferSize == 0; }
233 bool isReserved() const { return Unavailable; }
234
235 void setReserved() { Unavailable = true; }
236 void clearReserved() { Unavailable = false; }
237
238 /// Returs true if this resource is not reserved, and if there are at least
239 /// `NumUnits` available units.
240 LLVM_ABI bool isReady(unsigned NumUnits = 1) const;
241
242 uint64_t getNumReadyUnits() const { return llvm::popcount(ReadyMask); }
243
244 bool isAResourceGroup() const { return IsAGroup; }
245
246 bool containsResource(uint64_t ID) const { return ResourceMask & ID; }
247
248 void markSubResourceAsUsed(uint64_t ID) {
249 assert(isSubResourceReady(ID));
250 ReadyMask ^= ID;
251 }
252
253 void releaseSubResource(uint64_t ID) {
254 assert(!isSubResourceReady(ID));
255 ReadyMask ^= ID;
256 }
257
258 unsigned getNumUnits() const {
259 return isAResourceGroup() ? 1U : llvm::popcount(ResourceSizeMask);
260 }
261
262 /// Checks if there is an available slot in the resource buffer.
263 ///
264 /// Returns RS_BUFFER_AVAILABLE if this is not a buffered resource, or if
265 /// there is a slot available.
266 ///
267 /// Returns RS_RESERVED if this buffered resource is a dispatch hazard, and it
268 /// is reserved.
269 ///
270 /// Returns RS_BUFFER_UNAVAILABLE if there are no available slots.
271 LLVM_ABI ResourceStateEvent isBufferAvailable() const;
272
273 /// Reserve a buffer slot.
274 ///
275 /// Returns true if the buffer is not full.
276 /// It always returns true if BufferSize is set to zero.
277 bool reserveBuffer() {
278 if (BufferSize <= 0)
279 return true;
280
281 --AvailableSlots;
282 assert(AvailableSlots <= static_cast<unsigned>(BufferSize));
283 return AvailableSlots;
284 }
285
286 /// Releases a slot in the buffer.
287 void releaseBuffer() {
288 // Ignore dispatch hazards or invalid buffer sizes.
289 if (BufferSize <= 0)
290 return;
291
292 ++AvailableSlots;
293 assert(AvailableSlots <= static_cast<unsigned>(BufferSize));
294 }
295
296#ifndef NDEBUG
297 void dump() const;
298#endif
299};
300
301/// A resource unit identifier.
302///
303/// This is used to identify a specific processor resource unit using a pair
304/// of indices where the 'first' index is a processor resource mask, and the
305/// 'second' index is an index for a "sub-resource" (i.e. unit).
306typedef std::pair<uint64_t, uint64_t> ResourceRef;
307
308// First: a MCProcResourceDesc index identifying a buffered resource.
309// Second: max number of buffer entries used in this resource.
310typedef std::pair<unsigned, unsigned> BufferUsageEntry;
311
312/// A resource manager for processor resource units and groups.
313///
314/// This class owns all the ResourceState objects, and it is responsible for
315/// acting on requests from a Scheduler by updating the internal state of
316/// ResourceState objects.
317/// This class doesn't know about instruction itineraries and functional units.
318/// In future, it can be extended to support itineraries too through the same
319/// public interface.
320class ResourceManager {
321 // Set of resources available on the subtarget.
322 //
323 // There is an instance of ResourceState for every resource declared by the
324 // target scheduling model.
325 //
326 // Elements of this vector are ordered by resource kind. In particular,
327 // resource units take precedence over resource groups.
328 //
329 // The index of a processor resource in this vector depends on the value of
330 // its mask (see the description of field ResourceState::ResourceMask). In
331 // particular, it is computed as the position of the most significant bit set
332 // (MSB) in the mask plus one (since we want to ignore the invalid resource
333 // descriptor at index zero).
334 //
335 // Example (little endian):
336 //
337 // Resource | Mask | MSB | Index
338 // ---------+---------+---------+-------
339 // A | 0b00001 | 0b00001 | 1
340 // | | |
341 // B | 0b00100 | 0b00100 | 3
342 // | | |
343 // C | 0b10010 | 0b10000 | 5
344 //
345 //
346 // The same index is also used to address elements within vector `Strategies`
347 // and vector `Resource2Groups`.
348 std::vector<std::unique_ptr<ResourceState>> Resources;
349 std::vector<std::unique_ptr<ResourceStrategy>> Strategies;
350
351 // Used to quickly identify groups that own a particular resource unit.
352 std::vector<uint64_t> Resource2Groups;
353
354 // A table that maps processor resource IDs to processor resource masks.
355 SmallVector<uint64_t, 8> ProcResID2Mask;
356
357 // A table that maps resource indices to actual processor resource IDs in the
358 // scheduling model.
359 SmallVector<unsigned, 8> ResIndex2ProcResID;
360
361 // Keeps track of which resources are busy, and how many cycles are left
362 // before those become usable again.
364
365 // Set of processor resource units available on the target.
366 uint64_t ProcResUnitMask;
367
368 // Set of processor resource units that are available during this cycle.
369 uint64_t AvailableProcResUnits;
370
371 // Set of processor resources that are currently reserved.
372 uint64_t ReservedResourceGroups;
373
374 // Set of unavailable scheduler buffer resources. This is used internally to
375 // speedup `canBeDispatched()` queries.
376 uint64_t AvailableBuffers;
377
378 // Set of dispatch hazard buffer resources that are currently unavailable.
379 uint64_t ReservedBuffers;
380
381 // Returns the actual resource unit that will be used.
382 ResourceRef selectPipe(uint64_t ResourceID);
383
384 void use(const ResourceRef &RR);
385 void release(const ResourceRef &RR);
386
387 unsigned getNumUnits(uint64_t ResourceID) const;
388
389 // Overrides the selection strategy for the processor resource with the given
390 // mask.
391 LLVM_ABI void setCustomStrategyImpl(std::unique_ptr<ResourceStrategy> S,
392 uint64_t ResourceMask);
393
394public:
396 float ReservationStationScaleFactor);
397 virtual ~ResourceManager() = default;
398
399 // Overrides the selection strategy for the resource at index ResourceID in
400 // the MCProcResourceDesc table.
401 void setCustomStrategy(std::unique_ptr<ResourceStrategy> S,
402 unsigned ResourceID) {
403 assert(ResourceID < ProcResID2Mask.size() &&
404 "Invalid resource index in input!");
405 return setCustomStrategyImpl(std::move(S), ProcResID2Mask[ResourceID]);
406 }
407
408 // Returns RS_BUFFER_AVAILABLE if buffered resources are not reserved, and if
409 // there are enough available slots in the buffers.
410 LLVM_ABI ResourceStateEvent canBeDispatched(uint64_t ConsumedBuffers) const;
411
412 // Return the processor resource identifier associated to this Mask.
413 LLVM_ABI unsigned resolveResourceMask(uint64_t Mask) const;
414
415 // Acquires a slot from every buffered resource in mask `ConsumedBuffers`.
416 // Units that are dispatch hazards (i.e. BufferSize=0) are marked as reserved.
417 LLVM_ABI void reserveBuffers(uint64_t ConsumedBuffers);
418
419 // Releases a slot from every buffered resource in mask `ConsumedBuffers`.
420 // ConsumedBuffers is a bitmask of previously acquired buffers (using method
421 // `reserveBuffers`). Units that are dispatch hazards (i.e. BufferSize=0) are
422 // not automatically unreserved by this method.
423 LLVM_ABI void releaseBuffers(uint64_t ConsumedBuffers);
424
425 // Reserve a processor resource. A reserved resource is not available for
426 // instruction issue until it is released.
427 LLVM_ABI void reserveResource(uint64_t ResourceID);
428
429 // Release a previously reserved processor resource.
430 LLVM_ABI void releaseResource(uint64_t ResourceID);
431
432 // Returns a zero mask if resources requested by Desc are all available during
433 // this cycle. It returns a non-zero mask value only if there are unavailable
434 // processor resources; each bit set in the mask represents a busy processor
435 // resource unit or a reserved processor resource group.
436 LLVM_ABI uint64_t checkAvailability(const InstrDesc &Desc) const;
437
438 uint64_t getProcResUnitMask() const { return ProcResUnitMask; }
439 uint64_t getAvailableProcResUnits() const { return AvailableProcResUnits; }
440
441 using ResourceWithCycles = std::pair<ResourceRef, ReleaseAtCycles>;
442
443 void issueInstruction(const InstrDesc &Desc,
444 SmallVectorImpl<ResourceWithCycles> &Pipes) {
445 if (Desc.HasPartiallyOverlappingGroups)
446 return issueInstructionImpl(Desc, Pipes);
447
448 return fastIssueInstruction(Desc, Pipes);
449 }
450
451 // Selects pipeline resources consumed by an instruction.
452 // This method works under the assumption that used group resources don't
453 // partially overlap. The logic is guaranteed to find a valid resource unit
454 // schedule, no matter in which order individual uses are processed. For that
455 // reason, the vector of resource uses is simply (and quickly) processed in
456 // sequence. The resulting schedule is eventually stored into vector `Pipes`.
457 LLVM_ABI void
458 fastIssueInstruction(const InstrDesc &Desc,
459 SmallVectorImpl<ResourceWithCycles> &Pipes);
460
461 // Selects pipeline resources consumed by an instruction.
462 // This method works under the assumption that used resource groups may
463 // partially overlap. This complicates the selection process, because the
464 // order in which uses are processed matters. The logic internally prioritizes
465 // groups which are more constrained than others.
466 LLVM_ABI void
467 issueInstructionImpl(const InstrDesc &Desc,
468 SmallVectorImpl<ResourceWithCycles> &Pipes);
469
470 LLVM_ABI void cycleEvent(SmallVectorImpl<ResourceRef> &ResourcesFreed);
471
472#ifndef NDEBUG
473 void dump() const {
474 for (const std::unique_ptr<ResourceState> &Resource : Resources)
475 Resource->dump();
476 }
477#endif
478};
479} // namespace mca
480} // namespace llvm
481
482#endif // LLVM_MCA_HARDWAREUNITS_RESOURCEMANAGER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
#define LLVM_ABI
Definition Compiler.h:211
DXIL Remove Unused Resources
This file defines the DenseMap class.
@ Unavailable
We know the block is not fully available. This is a fixpoint.
Definition GVN.cpp:1231
Move duplicate certain instructions close to their use
Definition Localizer.cpp:78
This file defines abstractions used by the Pipeline to model register reads, register writes and inst...
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:156
Define a kind of processor resource that will be modeled by the scheduler.
Definition MCSchedule.h:43
Machine model for scheduling, bundling, and heuristics.
Definition MCSchedule.h:274