[llvm-mca] Move the logic that computes the scheduler's queue usage to the BackendStatistics view.
This patch introduces two new callbacks in the event listener interface to
handle the "buffered resource reserved" event and the "buffered resource
released" event. Every time a buffered resource is used, an event is generated.
Before this patch, the Scheduler (with the help of the ResourceManager) was
responsible for tracking the scheduler's queue usage. However, that design
forced the Scheduler to 'publish' scheduler's queue pressure information through
the Backend interface.
The goal of this patch is to break the dependency between the BackendStatistics
view, and the Backend. Now the Scheduler knows how to notify "buffer
reserved/released" events. The scheduler's queue usage analysis has been moved
to the BackendStatistics.
Differential Revision: https://reviews.llvm.org/D44686
llvm-svn: 328011
diff --git a/llvm/tools/llvm-mca/Scheduler.cpp b/llvm/tools/llvm-mca/Scheduler.cpp
index 4d7f1a2..8a42cd0 100644
--- a/llvm/tools/llvm-mca/Scheduler.cpp
+++ b/llvm/tools/llvm-mca/Scheduler.cpp
@@ -181,7 +181,6 @@
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 @@
// 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 @@
}
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 @@
// 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::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::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