summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/tools/llvm-mca/Backend.cpp10
-rw-r--r--llvm/tools/llvm-mca/Backend.h5
-rw-r--r--llvm/tools/llvm-mca/BackendStatistics.cpp41
-rw-r--r--llvm/tools/llvm-mca/BackendStatistics.h28
-rw-r--r--llvm/tools/llvm-mca/HWEventListener.h5
-rw-r--r--llvm/tools/llvm-mca/Scheduler.cpp54
-rw-r--r--llvm/tools/llvm-mca/Scheduler.h35
7 files changed, 119 insertions, 59 deletions
diff --git a/llvm/tools/llvm-mca/Backend.cpp b/llvm/tools/llvm-mca/Backend.cpp
index cad7db3c438..7d694667d7f 100644
--- a/llvm/tools/llvm-mca/Backend.cpp
+++ b/llvm/tools/llvm-mca/Backend.cpp
@@ -75,6 +75,16 @@ void Backend::notifyResourceAvailable(const ResourceRef &RR) {
Listener->onResourceAvailable(RR);
}
+void Backend::notifyReservedBuffers(ArrayRef<unsigned> Buffers) {
+ for (HWEventListener *Listener : Listeners)
+ Listener->onReservedBuffers(Buffers);
+}
+
+void Backend::notifyReleasedBuffers(ArrayRef<unsigned> Buffers) {
+ for (HWEventListener *Listener : Listeners)
+ Listener->onReleasedBuffers(Buffers);
+}
+
void Backend::notifyCycleEnd(unsigned Cycle) {
DEBUG(dbgs() << "[E] Cycle end: " << Cycle << "\n\n");
for (HWEventListener *Listener : Listeners)
diff --git a/llvm/tools/llvm-mca/Backend.h b/llvm/tools/llvm-mca/Backend.h
index e9cf529682e..513904bf6c6 100644
--- a/llvm/tools/llvm-mca/Backend.h
+++ b/llvm/tools/llvm-mca/Backend.h
@@ -94,15 +94,14 @@ public:
unsigned getMaxUsedRegisterMappings() const {
return DU->getMaxUsedRegisterMappings();
}
- void getBuffersUsage(std::vector<BufferUsageEntry> &Usage) const {
- return HWS->getBuffersUsage(Usage);
- }
void addEventListener(HWEventListener *Listener);
void notifyCycleBegin(unsigned Cycle);
void notifyInstructionEvent(const HWInstructionEvent &Event);
void notifyStallEvent(const HWStallEvent &Event);
void notifyResourceAvailable(const ResourceRef &RR);
+ void notifyReservedBuffers(llvm::ArrayRef<unsigned> Buffers);
+ void notifyReleasedBuffers(llvm::ArrayRef<unsigned> Buffers);
void notifyCycleEnd(unsigned Cycle);
};
diff --git a/llvm/tools/llvm-mca/BackendStatistics.cpp b/llvm/tools/llvm-mca/BackendStatistics.cpp
index 274f79913f2..64b8be11e4d 100644
--- a/llvm/tools/llvm-mca/BackendStatistics.cpp
+++ b/llvm/tools/llvm-mca/BackendStatistics.cpp
@@ -36,6 +36,29 @@ void BackendStatistics::onInstructionEvent(const HWInstructionEvent &Event) {
}
}
+void BackendStatistics::onReservedBuffers(ArrayRef<unsigned> Buffers) {
+ for (const unsigned Buffer : Buffers) {
+ if (BufferedResources.find(Buffer) != BufferedResources.end()) {
+ BufferUsage &BU = BufferedResources[Buffer];
+ BU.SlotsInUse++;
+ BU.MaxUsedSlots = std::max(BU.MaxUsedSlots, BU.SlotsInUse);
+ continue;
+ }
+
+ BufferedResources.insert(
+ std::pair<unsigned, BufferUsage>(Buffer, {1U, 1U}));
+ }
+}
+
+void BackendStatistics::onReleasedBuffers(ArrayRef<unsigned> Buffers) {
+ for (const unsigned Buffer : Buffers) {
+ assert(BufferedResources.find(Buffer) != BufferedResources.end() &&
+ "Buffered resource not in map?");
+ BufferUsage &BU = BufferedResources[Buffer];
+ BU.SlotsInUse--;
+ }
+}
+
void BackendStatistics::printRetireUnitStatistics(llvm::raw_ostream &OS) const {
std::string Buffer;
raw_string_ostream TempStream(Buffer);
@@ -126,15 +149,13 @@ void BackendStatistics::printDispatchStalls(raw_ostream &OS) const {
OS << Buffer;
}
-void BackendStatistics::printSchedulerUsage(
- raw_ostream &OS, const MCSchedModel &SM,
- const ArrayRef<BufferUsageEntry> &Usage) const {
-
+void BackendStatistics::printSchedulerUsage(raw_ostream &OS,
+ const MCSchedModel &SM) const {
std::string Buffer;
raw_string_ostream TempStream(Buffer);
TempStream << "\n\nScheduler's queue usage:\n";
// Early exit if no buffered resources were consumed.
- if (Usage.empty()) {
+ if (BufferedResources.empty()) {
TempStream << "No scheduler resources used.\n";
TempStream.flush();
OS << Buffer;
@@ -143,17 +164,15 @@ void BackendStatistics::printSchedulerUsage(
for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
- if (!ProcResource.BufferSize)
+ if (ProcResource.BufferSize <= 0)
continue;
- for (const BufferUsageEntry &Entry : Usage)
- if (I == Entry.first)
- TempStream << ProcResource.Name << ", " << Entry.second << '/'
- << ProcResource.BufferSize << '\n';
+ const BufferUsage &BU = BufferedResources.lookup(I);
+ TempStream << ProcResource.Name << ", " << BU.MaxUsedSlots << '/'
+ << ProcResource.BufferSize << '\n';
}
TempStream.flush();
OS << Buffer;
}
-
} // namespace mca
diff --git a/llvm/tools/llvm-mca/BackendStatistics.h b/llvm/tools/llvm-mca/BackendStatistics.h
index dacf5b0cac1..0def7226fae 100644
--- a/llvm/tools/llvm-mca/BackendStatistics.h
+++ b/llvm/tools/llvm-mca/BackendStatistics.h
@@ -85,6 +85,17 @@ class BackendStatistics : public View {
// is one counter for every generic stall kind (see class HWStallEvent).
llvm::SmallVector<unsigned, 8> HWStalls;
+ // Tracks the usage of a scheduler's queue.
+ struct BufferUsage {
+ unsigned SlotsInUse;
+ unsigned MaxUsedSlots;
+ };
+
+ // There is a map entry for each buffered resource in the scheduling model.
+ // Every time a buffer is consumed/freed, this view updates the corresponding
+ // entry.
+ llvm::DenseMap<unsigned, BufferUsage> BufferedResources;
+
void updateHistograms() {
DispatchGroupSizePerCycle[NumDispatched]++;
IssuedPerCycle[NumIssued]++;
@@ -107,8 +118,8 @@ class BackendStatistics : public View {
unsigned Cycles) const;
void printIssuePerCycle(const Histogram &IssuePerCycle,
unsigned TotalCycles) const;
- void printSchedulerUsage(llvm::raw_ostream &OS, const llvm::MCSchedModel &SM,
- const llvm::ArrayRef<BufferUsageEntry> &Usage) const;
+ void printSchedulerUsage(llvm::raw_ostream &OS,
+ const llvm::MCSchedModel &SM) const;
public:
BackendStatistics(const Backend &backend, const llvm::MCSubtargetInfo &sti)
@@ -126,6 +137,14 @@ public:
HWStalls[Event.Type]++;
}
+ // Increases the number of used scheduler queue slots of every buffered
+ // resource in the Buffers set.
+ void onReservedBuffers(llvm::ArrayRef<unsigned> Buffers);
+
+ // Decreases by one the number of used scheduler queue slots of every
+ // buffered resource in the Buffers set.
+ void onReleasedBuffers(llvm::ArrayRef<unsigned> Buffers);
+
void printView(llvm::raw_ostream &OS) const override {
printDispatchStalls(OS);
printRATStatistics(OS, B.getTotalRegisterMappingsCreated(),
@@ -134,12 +153,9 @@ public:
printSchedulerStatistics(OS);
printRetireUnitStatistics(OS);
- std::vector<BufferUsageEntry> Usage;
- B.getBuffersUsage(Usage);
- printSchedulerUsage(OS, STI.getSchedModel(), Usage);
+ printSchedulerUsage(OS, STI.getSchedModel());
}
};
-
} // namespace mca
#endif
diff --git a/llvm/tools/llvm-mca/HWEventListener.h b/llvm/tools/llvm-mca/HWEventListener.h
index e5fb79414e0..9b8ba124ce4 100644
--- a/llvm/tools/llvm-mca/HWEventListener.h
+++ b/llvm/tools/llvm-mca/HWEventListener.h
@@ -104,6 +104,11 @@ public:
using ResourceRef = std::pair<uint64_t, uint64_t>;
virtual void onResourceAvailable(const ResourceRef &RRef) {}
+ // Events generated by the Scheduler when buffered resources are
+ // consumed/freed.
+ virtual void onReservedBuffers(llvm::ArrayRef<unsigned> Buffers) {}
+ virtual void onReleasedBuffers(llvm::ArrayRef<unsigned> Buffers) {}
+
virtual ~HWEventListener() {}
private:
diff --git a/llvm/tools/llvm-mca/Scheduler.cpp b/llvm/tools/llvm-mca/Scheduler.cpp
index 4d7f1a222ca..8a42cd0877a 100644
--- a/llvm/tools/llvm-mca/Scheduler.cpp
+++ b/llvm/tools/llvm-mca/Scheduler.cpp
@@ -181,7 +181,6 @@ bool ResourceManager::mustIssueImmediately(const InstrDesc &Desc) {
void ResourceManager::issueInstruction(
unsigned Index, const InstrDesc &Desc,
SmallVectorImpl<std::pair<ResourceRef, unsigned>> &Pipes) {
- releaseBuffers(Desc.Buffers);
for (const std::pair<uint64_t, ResourceUsage> &R : Desc.Resources) {
const CycleSegment &CS = R.second.CS;
if (!CS.size()) {
@@ -252,11 +251,14 @@ void Scheduler::scheduleInstruction(unsigned Idx, Instruction &MCIS) {
// Consume entries in the reservation stations.
const InstrDesc &Desc = MCIS.getDesc();
- // Reserve a slot in each buffered resource. Also, mark units with
- // BufferSize=0 as reserved. Resources with a buffer size of zero will only be
- // released after MCIS is issued, and all the ResourceCycles for those units
- // have been consumed.
- Resources->reserveBuffers(Desc.Buffers);
+ if (!Desc.Buffers.empty()) {
+ // Reserve a slot in each buffered resource. Also, mark units with
+ // BufferSize=0 as reserved. Resources with a buffer size of zero will only
+ // be released after MCIS is issued, and all the ResourceCycles for those
+ // units have been consumed.
+ Resources->reserveBuffers(Desc.Buffers);
+ notifyReservedBuffers(Desc.Buffers);
+ }
bool MayLoad = Desc.MayLoad;
bool MayStore = Desc.MayStore;
@@ -331,6 +333,13 @@ Scheduler::Event Scheduler::canBeDispatched(const InstrDesc &Desc) const {
}
void Scheduler::issueInstruction(Instruction &IS, unsigned InstrIndex) {
+ const InstrDesc &D = IS.getDesc();
+
+ if (!D.Buffers.empty()) {
+ Resources->releaseBuffers(D.Buffers);
+ notifyReleasedBuffers(D.Buffers);
+ }
+
// Issue the instruction and collect all the consumed resources
// into a vector. That vector is then used to notify the listener.
// Most instructions consume very few resurces (typically one or
@@ -338,8 +347,6 @@ void Scheduler::issueInstruction(Instruction &IS, unsigned InstrIndex) {
// initialize its capacity to 4. This should address the majority of
// the cases.
SmallVector<std::pair<ResourceRef, unsigned>, 4> UsedResources;
-
- const InstrDesc &D = IS.getDesc();
Resources->issueInstruction(InstrIndex, D, UsedResources);
// Notify the instruction that it started executing.
// This updates the internal state of each write.
@@ -417,13 +424,14 @@ void Scheduler::updateIssuedQueue() {
void Scheduler::notifyInstructionIssued(
unsigned Index, const ArrayRef<std::pair<ResourceRef, unsigned>> &Used) {
- DEBUG(dbgs() << "[E] Instruction Issued: " << Index << '\n';
- for (const std::pair<ResourceRef, unsigned> &Resource
- : Used) {
- dbgs() << "[E] Resource Used: [" << Resource.first.first << '.'
- << Resource.first.second << "]\n";
- dbgs() << " cycles: " << Resource.second << '\n';
- });
+ DEBUG({
+ dbgs() << "[E] Instruction Issued: " << Index << '\n';
+ for (const std::pair<ResourceRef, unsigned> &Resource : Used) {
+ dbgs() << "[E] Resource Used: [" << Resource.first.first << '.'
+ << Resource.first.second << "]\n";
+ dbgs() << " cycles: " << Resource.second << '\n';
+ }
+ });
Owner->notifyInstructionEvent(HWInstructionIssuedEvent(Index, Used));
}
@@ -446,4 +454,20 @@ void Scheduler::notifyInstructionReady(unsigned Index) {
void Scheduler::notifyResourceAvailable(const ResourceRef &RR) {
Owner->notifyResourceAvailable(RR);
}
+
+void Scheduler::notifyReservedBuffers(ArrayRef<uint64_t> Buffers) {
+ SmallVector<unsigned, 4> BufferIDs(Buffers.begin(), Buffers.end());
+ std::transform(
+ Buffers.begin(), Buffers.end(), BufferIDs.begin(),
+ [&](uint64_t Op) { return Resources->resolveResourceMask(Op); });
+ Owner->notifyReservedBuffers(BufferIDs);
+}
+
+void Scheduler::notifyReleasedBuffers(ArrayRef<uint64_t> Buffers) {
+ SmallVector<unsigned, 4> BufferIDs(Buffers.begin(), Buffers.end());
+ std::transform(
+ Buffers.begin(), Buffers.end(), BufferIDs.begin(),
+ [&](uint64_t Op) { return Resources->resolveResourceMask(Op); });
+ Owner->notifyReleasedBuffers(BufferIDs);
+}
} // namespace mca
diff --git a/llvm/tools/llvm-mca/Scheduler.h b/llvm/tools/llvm-mca/Scheduler.h
index c74d3f1e196..93c5295e8d5 100644
--- a/llvm/tools/llvm-mca/Scheduler.h
+++ b/llvm/tools/llvm-mca/Scheduler.h
@@ -138,11 +138,6 @@ class ResourceState {
// Available slots in the buffer (zero, if this is not a buffered resource).
unsigned AvailableSlots;
- // Maximum number of buffer slots seen used during one cycle.
- // This helps tracking dynamic dispatch stalls caused by the lack of
- // entries in the scheduler's queue.
- unsigned MaxUsedSlots;
-
// 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
@@ -182,14 +177,12 @@ public:
ReadyMask = ResourceSizeMask;
BufferSize = Desc.BufferSize;
AvailableSlots = BufferSize == -1 ? 0U : static_cast<unsigned>(BufferSize);
- MaxUsedSlots = 0;
Unavailable = false;
}
unsigned getProcResourceID() const { return ProcResourceDescIndex; }
uint64_t getResourceMask() const { return ResourceMask; }
int getBufferSize() const { return BufferSize; }
- unsigned getMaxUsedSlots() const { return MaxUsedSlots; }
bool isBuffered() const { return BufferSize > 0; }
bool isInOrder() const { return BufferSize == 1; }
@@ -244,8 +237,6 @@ public:
void reserveBuffer() {
if (AvailableSlots)
AvailableSlots--;
- unsigned UsedSlots = static_cast<unsigned>(BufferSize) - AvailableSlots;
- MaxUsedSlots = std::max(MaxUsedSlots, UsedSlots);
}
void releaseBuffer() {
@@ -339,8 +330,12 @@ public:
// Returns RS_BUFFER_AVAILABLE if buffered resources are not reserved, and if
// there are enough available slots in the buffers.
- ResourceStateEvent
- canBeDispatched(const llvm::ArrayRef<uint64_t> Buffers) const;
+ ResourceStateEvent canBeDispatched(llvm::ArrayRef<uint64_t> Buffers) const;
+
+ // Return the processor resource identifier associated to this Mask.
+ unsigned resolveResourceMask(uint64_t Mask) const {
+ return Resources.find(Mask)->second->getProcResourceID();
+ }
// Consume a slot in every buffered resource from array 'Buffers'. Resource
// units that are dispatch hazards (i.e. BufferSize=0) are marked as reserved.
@@ -372,15 +367,6 @@ public:
void cycleEvent(llvm::SmallVectorImpl<ResourceRef> &ResourcesFreed);
- void getBuffersUsage(std::vector<BufferUsageEntry> &Usage) const {
- for (const std::pair<uint64_t, UniqueResourceState> &Resource : Resources) {
- const ResourceState &RS = *Resource.second;
- if (RS.isBuffered())
- Usage.emplace_back(std::pair<unsigned, unsigned>(RS.getProcResourceID(),
- RS.getMaxUsedSlots()));
- }
- }
-
#ifndef NDEBUG
void dump() const {
for (const std::pair<uint64_t, UniqueResourceState> &Resource : Resources)
@@ -439,6 +425,11 @@ class Scheduler {
void notifyInstructionReady(unsigned Index);
void notifyResourceAvailable(const ResourceRef &RR);
+ // Notify the Backend that buffered resources were consumed.
+ void notifyReservedBuffers(llvm::ArrayRef<uint64_t> Buffers);
+ // Notify the Backend that buffered resources were freed.
+ void notifyReleasedBuffers(llvm::ArrayRef<uint64_t> Buffers);
+
/// Issue instructions from the ready queue by giving priority to older
/// instructions.
void issue();
@@ -498,10 +489,6 @@ public:
void cycleEvent(unsigned Cycle);
- void getBuffersUsage(std::vector<BufferUsageEntry> &Usage) const {
- Resources->getBuffersUsage(Usage);
- }
-
#ifndef NDEBUG
void dump() const;
#endif
OpenPOWER on IntegriCloud