forked from OSchip/llvm-project
[llvm-mca] Improved code comments and moved some method definitions from Scheduler.h to Scheduler.cpp. NFC
llvm-svn: 340395
This commit is contained in:
parent
707f7619e3
commit
4660fd25d1
|
@ -22,6 +22,34 @@ using namespace llvm;
|
|||
|
||||
#define DEBUG_TYPE "llvm-mca"
|
||||
|
||||
ResourceState::ResourceState(const llvm::MCProcResourceDesc &Desc,
|
||||
unsigned Index, uint64_t Mask)
|
||||
: ProcResourceDescIndex(Index), ResourceMask(Mask) {
|
||||
if (llvm::countPopulation(ResourceMask) > 1)
|
||||
ResourceSizeMask = ResourceMask ^ llvm::PowerOf2Floor(ResourceMask);
|
||||
else
|
||||
ResourceSizeMask = (1ULL << Desc.NumUnits) - 1;
|
||||
NextInSequenceMask = ResourceSizeMask;
|
||||
RemovedFromNextInSequence = 0;
|
||||
ReadyMask = ResourceSizeMask;
|
||||
BufferSize = Desc.BufferSize;
|
||||
AvailableSlots = BufferSize == -1 ? 0U : static_cast<unsigned>(BufferSize);
|
||||
Unavailable = false;
|
||||
}
|
||||
|
||||
bool ResourceState::isReady(unsigned NumUnits) const {
|
||||
return (!isReserved() || isADispatchHazard()) &&
|
||||
llvm::countPopulation(ReadyMask) >= NumUnits;
|
||||
}
|
||||
|
||||
ResourceStateEvent ResourceState::isBufferAvailable() const {
|
||||
if (isADispatchHazard() && isReserved())
|
||||
return RS_RESERVED;
|
||||
if (!isBuffered() || AvailableSlots)
|
||||
return RS_BUFFER_AVAILABLE;
|
||||
return RS_BUFFER_UNAVAILABLE;
|
||||
}
|
||||
|
||||
uint64_t ResourceState::selectNextInSequence() {
|
||||
assert(isReady());
|
||||
uint64_t Next = getNextInSequence();
|
||||
|
@ -308,8 +336,7 @@ void Scheduler::issueInstructionImpl(
|
|||
|
||||
// Release the buffered resources and issue the instruction.
|
||||
void Scheduler::issueInstruction(
|
||||
InstRef &IR,
|
||||
SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources,
|
||||
InstRef &IR, SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources,
|
||||
SmallVectorImpl<InstRef> &ReadyInstructions) {
|
||||
const Instruction &Inst = *IR.getInstruction();
|
||||
bool HasDependentUsers = Inst.hasDependentUsers();
|
||||
|
|
|
@ -46,31 +46,27 @@ enum ResourceStateEvent {
|
|||
RS_RESERVED
|
||||
};
|
||||
|
||||
/// A descriptor for processor resources.
|
||||
/// A processor resource descriptor.
|
||||
///
|
||||
/// Each object of class ResourceState is associated to a specific processor
|
||||
/// resource. There is an instance of this class for every processor resource
|
||||
/// defined by the scheduling model.
|
||||
/// A ResourceState dynamically tracks the availability of units of a processor
|
||||
/// resource. For example, the ResourceState of a ProcResGroup tracks the
|
||||
/// availability of resource units which are part of the group.
|
||||
///
|
||||
/// Internally, ResourceState uses a round-robin selector to identify
|
||||
/// which unit of the group shall be used next.
|
||||
/// There is an instance of this class for every processor resource defined by
|
||||
/// the machine scheduling model.
|
||||
/// Objects of class ResourceState dynamically track the usage of processor
|
||||
/// resource units.
|
||||
class ResourceState {
|
||||
// Index to the MCProcResourceDesc in the processor Model.
|
||||
/// An index to the MCProcResourceDesc entry in the processor model.
|
||||
unsigned ProcResourceDescIndex;
|
||||
// A resource mask. This is generated by the tool with the help of
|
||||
// function `mca::createProcResourceMasks' (see Support.h).
|
||||
/// A resource mask. This is generated by the tool with the help of
|
||||
/// function `mca::createProcResourceMasks' (see Support.h).
|
||||
uint64_t ResourceMask;
|
||||
|
||||
// A ProcResource can specify a number of units. For the purpose of dynamic
|
||||
// scheduling, a processor resource with more than one unit behaves like a
|
||||
// group. This field has one bit set for every unit/resource that is part of
|
||||
// the group.
|
||||
// For groups, this field defaults to 'ResourceMask'. For non-group
|
||||
// resources, the number of bits set in this mask is equivalent to the
|
||||
// number of units (i.e. field 'NumUnits' in 'ProcResourceUnits').
|
||||
/// A ProcResource can have multiple units.
|
||||
///
|
||||
/// For processor resource groups,
|
||||
/// this field default to the value of field `ResourceMask`; the number of
|
||||
/// bits set is equal to the cardinality of the group. For normal (i.e.
|
||||
/// non-group) resources, the number of bits set in this mask is equivalent
|
||||
/// to the number of units declared by the processor model (see field
|
||||
/// 'NumUnits' in 'ProcResourceUnits').
|
||||
uint64_t ResourceSizeMask;
|
||||
|
||||
// A simple round-robin selector for processor resources.
|
||||
|
@ -89,10 +85,9 @@ class ResourceState {
|
|||
//
|
||||
// NextInSequenceMask -- 0b111
|
||||
//
|
||||
// Field NextInSequenceMask is used by the resource manager (i.e.
|
||||
// an object of class ResourceManager) to select the "next available resource"
|
||||
// from the set. The algorithm would prioritize resources with a bigger
|
||||
// ResourceMask value.
|
||||
// Field NextInSequenceMask is used by class ResourceManager to select the
|
||||
// "next available resource" from the set. The algorithm would prioritizes
|
||||
// resources with a bigger ResourceMask value.
|
||||
//
|
||||
// In this example, there are three resources in the set, and 'ResourceC'
|
||||
// has the highest mask value. The round-robin selector would firstly select
|
||||
|
@ -121,30 +116,39 @@ class ResourceState {
|
|||
// removes any bits which are set in RemoveFromNextInSequence.
|
||||
uint64_t RemovedFromNextInSequence;
|
||||
|
||||
// A mask of ready units.
|
||||
/// A mask of ready units.
|
||||
uint64_t ReadyMask;
|
||||
|
||||
// Buffered resources will have this field set to a positive number bigger
|
||||
// than 0. A buffered resource behaves like a separate reservation station
|
||||
// implementing its own buffer for out-of-order execution.
|
||||
// A buffer of 1 is for units that force in-order execution.
|
||||
// A value of 0 is treated specially. In particular, a resource with
|
||||
// A BufferSize = 0 is for an in-order issue/dispatch resource.
|
||||
// That means, this resource is reserved starting from the dispatch event,
|
||||
// until all the "resource cycles" are consumed after the issue event.
|
||||
// While this resource is reserved, no other instruction may be dispatched.
|
||||
/// Buffered resources will have this field set to a positive number different
|
||||
/// than zero. A buffered resource behaves like a reservation station
|
||||
/// implementing its own buffer for out-of-order execution.
|
||||
///
|
||||
/// A BufferSize of 1 is used by scheduler resources that force in-order
|
||||
/// execution.
|
||||
///
|
||||
/// A BufferSize of 0 is used to model in-order issue/dispatch resources.
|
||||
/// Since in-order issue/dispatch resources don't implement buffers, dispatch
|
||||
/// events coincide with issue events.
|
||||
/// Also, no other instruction ca be dispatched/issue while this resource is
|
||||
/// in use. Only when all the "resource cycles" are consumed (after the issue
|
||||
/// event), a new instruction ca be dispatched.
|
||||
int BufferSize;
|
||||
|
||||
// Available slots in the buffer (zero, if this is not a buffered resource).
|
||||
/// Available slots in the buffer (zero, if this is not a buffered resource).
|
||||
unsigned AvailableSlots;
|
||||
|
||||
// True if this is resource is currently unavailable.
|
||||
// An instruction may "reserve" a resource for a number of cycles.
|
||||
// During those cycles, the reserved resource cannot be used for other
|
||||
// instructions, even if the ReadyMask is set.
|
||||
/// This field is set if this resource is currently reserved.
|
||||
///
|
||||
/// Resources can be reserved for a number of cycles.
|
||||
/// Instructions can still be dispatched to reserved resources. However,
|
||||
/// istructions dispatched to a reserved resource cannot be issued to the
|
||||
/// underlying units (i.e. pipelines) until the resource is released.
|
||||
bool Unavailable;
|
||||
|
||||
bool isSubResourceReady(uint64_t ID) const { return ReadyMask & ID; }
|
||||
/// Checks for the availability of unit 'SubResMask' in the group.
|
||||
bool isSubResourceReady(uint64_t SubResMask) const {
|
||||
return ReadyMask & SubResMask;
|
||||
}
|
||||
|
||||
/// Returns the mask identifier of the next available resource in the set.
|
||||
uint64_t getNextInSequence() const {
|
||||
|
@ -160,25 +164,9 @@ class ResourceState {
|
|||
NextInSequenceMask = ResourceSizeMask;
|
||||
}
|
||||
|
||||
uint64_t computeResourceSizeMaskForGroup(uint64_t ResourceMask) {
|
||||
assert(llvm::countPopulation(ResourceMask) > 1);
|
||||
return ResourceMask ^ llvm::PowerOf2Floor(ResourceMask);
|
||||
}
|
||||
|
||||
public:
|
||||
ResourceState(const llvm::MCProcResourceDesc &Desc, unsigned Index,
|
||||
uint64_t Mask)
|
||||
: ProcResourceDescIndex(Index), ResourceMask(Mask) {
|
||||
bool IsAGroup = llvm::countPopulation(ResourceMask) > 1;
|
||||
ResourceSizeMask = IsAGroup ? computeResourceSizeMaskForGroup(ResourceMask)
|
||||
: ((1ULL << Desc.NumUnits) - 1);
|
||||
NextInSequenceMask = ResourceSizeMask;
|
||||
RemovedFromNextInSequence = 0;
|
||||
ReadyMask = ResourceSizeMask;
|
||||
BufferSize = Desc.BufferSize;
|
||||
AvailableSlots = BufferSize == -1 ? 0U : static_cast<unsigned>(BufferSize);
|
||||
Unavailable = false;
|
||||
}
|
||||
uint64_t Mask);
|
||||
|
||||
unsigned getProcResourceID() const { return ProcResourceDescIndex; }
|
||||
uint64_t getResourceMask() const { return ResourceMask; }
|
||||
|
@ -186,28 +174,25 @@ public:
|
|||
|
||||
bool isBuffered() const { return BufferSize > 0; }
|
||||
bool isInOrder() const { return BufferSize == 1; }
|
||||
|
||||
/// Returns true if this is an in-order dispatch/issue resource.
|
||||
bool isADispatchHazard() const { return BufferSize == 0; }
|
||||
bool isReserved() const { return Unavailable; }
|
||||
|
||||
void setReserved() { Unavailable = true; }
|
||||
void clearReserved() { Unavailable = false; }
|
||||
|
||||
// A resource is ready if it is not reserved, and if there are enough
|
||||
// available units.
|
||||
// If a resource is also a dispatch hazard, then we don't check if
|
||||
// it is reserved because that check would always return true.
|
||||
// A resource marked as "dispatch hazard" is always reserved at
|
||||
// dispatch time. When this method is called, the assumption is that
|
||||
// the user of this resource has been already dispatched.
|
||||
bool isReady(unsigned NumUnits = 1) const {
|
||||
return (!isReserved() || isADispatchHazard()) &&
|
||||
llvm::countPopulation(ReadyMask) >= NumUnits;
|
||||
}
|
||||
/// Returs true if this resource is not reserved, and if there are at least
|
||||
/// `NumUnits` available units.
|
||||
bool isReady(unsigned NumUnits = 1) const;
|
||||
|
||||
bool isAResourceGroup() const {
|
||||
return llvm::countPopulation(ResourceMask) > 1;
|
||||
}
|
||||
|
||||
bool containsResource(uint64_t ID) const { return ResourceMask & ID; }
|
||||
bool containsResource(uint64_t ID) const {
|
||||
return ResourceMask & ID;
|
||||
}
|
||||
|
||||
void markSubResourceAsUsed(uint64_t ID) {
|
||||
assert(isSubResourceReady(ID));
|
||||
|
@ -226,19 +211,24 @@ public:
|
|||
uint64_t selectNextInSequence();
|
||||
void removeFromNextInSequence(uint64_t ID);
|
||||
|
||||
ResourceStateEvent isBufferAvailable() const {
|
||||
if (isADispatchHazard() && isReserved())
|
||||
return RS_RESERVED;
|
||||
if (!isBuffered() || AvailableSlots)
|
||||
return RS_BUFFER_AVAILABLE;
|
||||
return RS_BUFFER_UNAVAILABLE;
|
||||
}
|
||||
/// Checks if there is an available slot in the resource buffer.
|
||||
///
|
||||
/// Returns RS_BUFFER_AVAILABLE if this is not a buffered resource, or if
|
||||
/// there is a slot available.
|
||||
///
|
||||
/// Returns RS_RESERVED if this buffered resource is a dispatch hazard, and it
|
||||
/// is reserved.
|
||||
///
|
||||
/// Returns RS_BUFFER_UNAVAILABLE if there are no available slots.
|
||||
ResourceStateEvent isBufferAvailable() const;
|
||||
|
||||
/// Reserve a slot in the buffer.
|
||||
void reserveBuffer() {
|
||||
if (AvailableSlots)
|
||||
AvailableSlots--;
|
||||
}
|
||||
|
||||
/// Release a slot in the buffer.
|
||||
void releaseBuffer() {
|
||||
if (BufferSize > 0)
|
||||
AvailableSlots++;
|
||||
|
@ -427,8 +417,7 @@ class Scheduler : public HardwareUnit {
|
|||
|
||||
public:
|
||||
Scheduler(const llvm::MCSchedModel &Model, LSUnit *Lsu)
|
||||
: LSU(Lsu),
|
||||
Strategy(llvm::make_unique<DefaultSchedulerStrategy>()),
|
||||
: LSU(Lsu), Strategy(llvm::make_unique<DefaultSchedulerStrategy>()),
|
||||
Resources(llvm::make_unique<ResourceManager>(Model)) {}
|
||||
Scheduler(const llvm::MCSchedModel &Model, LSUnit *Lsu,
|
||||
std::unique_ptr<SchedulerStrategy> SelectStrategy)
|
||||
|
@ -473,7 +462,8 @@ public:
|
|||
/// Issue an instruction and populates a vector of used pipeline resources,
|
||||
/// and a vector of instructions that transitioned to the ready state as a
|
||||
/// result of this event.
|
||||
void issueInstruction(InstRef &IR,
|
||||
void
|
||||
issueInstruction(InstRef &IR,
|
||||
llvm::SmallVectorImpl<std::pair<ResourceRef, double>> &Used,
|
||||
llvm::SmallVectorImpl<InstRef> &Ready);
|
||||
|
||||
|
|
Loading…
Reference in New Issue