[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:
Andrea Di Biagio 2018-08-22 10:23:28 +00:00
parent 707f7619e3
commit 4660fd25d1
2 changed files with 98 additions and 81 deletions

View File

@ -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();

View File

@ -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);