1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

[llvm-mca] Add pipeline stall events.

This patch introduces a new class named HWStallEvent (see HWEventListener.h),
and updates the event listener interface. A HWStallEvent represents a pipeline
stall caused by the lack of hardware resources. Similarly to HWInstructionEvent,
the event type is an unsigned, and the exact meaning depends on the subtarget.
At the moment, HWStallEvent supports a few generic dispatch events.

The main goals of this patch is to remove the logic that counts dispatch stalls
from the DispatchUnit to the BackendStatistics view.

Previously, DispatchUnit was responsible for counting and classifying dispatch
stall events. With this patch, we delegate the task of counting and classifying
stall events to the listeners (i.e. in our case, it is view
"BackendStatistics"). So, the DispatchUnit doesn't have to do extra
(unnecessary) bookkeeping.

This patch also helps futher simplifying the Backend interface. Now class
BackendStatistics no longer has to query the Backend interface to obtain the
number of dispatch stalls. As a consequence, we can get rid of all the
'getNumXXX()' methods from class Backend.
The long term goal is to remove all the remaining dependencies between the
Backend and the BackendStatistics interface.

Differential Revision: https://reviews.llvm.org/D44621

llvm-svn: 327837
This commit is contained in:
Andrea Di Biagio 2018-03-19 13:23:07 +00:00
parent 427bdf8c01
commit ed37aa59f3
7 changed files with 79 additions and 118 deletions

View File

@ -36,7 +36,8 @@ void Backend::runCycle(unsigned Cycle) {
std::unique_ptr<Instruction> NewIS( std::unique_ptr<Instruction> NewIS(
IB->createInstruction(STI, IR.first, *IR.second)); IB->createInstruction(STI, IR.first, *IR.second));
const InstrDesc &Desc = NewIS->getDesc(); const InstrDesc &Desc = NewIS->getDesc();
if (!DU->isAvailable(Desc.NumMicroOps) || !DU->canDispatch(*NewIS)) if (!DU->isAvailable(Desc.NumMicroOps) ||
!DU->canDispatch(IR.first, *NewIS))
break; break;
Instruction *IS = NewIS.get(); Instruction *IS = NewIS.get();
@ -62,6 +63,11 @@ void Backend::notifyInstructionEvent(const HWInstructionEvent &Event) {
Listener->onInstructionEvent(Event); Listener->onInstructionEvent(Event);
} }
void Backend::notifyStallEvent(const HWStallEvent &Event) {
for (HWEventListener *Listener : Listeners)
Listener->onStallEvent(Event);
}
void Backend::notifyResourceAvailable(const ResourceRef &RR) { void Backend::notifyResourceAvailable(const ResourceRef &RR) {
DEBUG(dbgs() << "[E] Resource Available: [" << RR.first << '.' << RR.second DEBUG(dbgs() << "[E] Resource Available: [" << RR.first << '.' << RR.second
<< "]\n"); << "]\n");

View File

@ -24,6 +24,7 @@ namespace mca {
class HWEventListener; class HWEventListener;
class HWInstructionEvent; class HWInstructionEvent;
class HWStallEvent;
/// \brief An out of order backend for a specific subtarget. /// \brief An out of order backend for a specific subtarget.
/// ///
@ -97,18 +98,10 @@ public:
return HWS->getBuffersUsage(Usage); return HWS->getBuffersUsage(Usage);
} }
unsigned getNumRATStalls() const { return DU->getNumRATStalls(); }
unsigned getNumRCUStalls() const { return DU->getNumRCUStalls(); }
unsigned getNumSQStalls() const { return DU->getNumSQStalls(); }
unsigned getNumLDQStalls() const { return DU->getNumLDQStalls(); }
unsigned getNumSTQStalls() const { return DU->getNumSTQStalls(); }
unsigned getNumDispatchGroupStalls() const {
return DU->getNumDispatchGroupStalls();
}
void addEventListener(HWEventListener *Listener); void addEventListener(HWEventListener *Listener);
void notifyCycleBegin(unsigned Cycle); void notifyCycleBegin(unsigned Cycle);
void notifyInstructionEvent(const HWInstructionEvent &Event); void notifyInstructionEvent(const HWInstructionEvent &Event);
void notifyStallEvent(const HWStallEvent &Event);
void notifyResourceAvailable(const ResourceRef &RR); void notifyResourceAvailable(const ResourceRef &RR);
void notifyCycleEnd(unsigned Cycle); void notifyCycleEnd(unsigned Cycle);
}; };

View File

@ -105,27 +105,22 @@ void BackendStatistics::printRATStatistics(raw_ostream &OS,
OS << Buffer; OS << Buffer;
} }
void BackendStatistics::printDispatchStalls(raw_ostream &OS, unsigned RATStalls, void BackendStatistics::printDispatchStalls(raw_ostream &OS) const {
unsigned RCUStalls,
unsigned SCHEDQStalls,
unsigned LDQStalls,
unsigned STQStalls,
unsigned DGStalls) const {
std::string Buffer; std::string Buffer;
raw_string_ostream TempStream(Buffer); raw_string_ostream TempStream(Buffer);
TempStream << "\n\nDynamic Dispatch Stall Cycles:\n"; TempStream << "\n\nDynamic Dispatch Stall Cycles:\n";
TempStream << "RAT - Register unavailable: " TempStream << "RAT - Register unavailable: "
<< RATStalls; << HWStalls[HWStallEvent::RegisterFileStall];
TempStream << "\nRCU - Retire tokens unavailable: " TempStream << "\nRCU - Retire tokens unavailable: "
<< RCUStalls; << HWStalls[HWStallEvent::RetireControlUnitStall];
TempStream << "\nSCHEDQ - Scheduler full: " TempStream << "\nSCHEDQ - Scheduler full: "
<< SCHEDQStalls; << HWStalls[HWStallEvent::SchedulerQueueFull];
TempStream << "\nLQ - Load queue full: " TempStream << "\nLQ - Load queue full: "
<< LDQStalls; << HWStalls[HWStallEvent::LoadQueueFull];
TempStream << "\nSQ - Store queue full: " TempStream << "\nSQ - Store queue full: "
<< STQStalls; << HWStalls[HWStallEvent::StoreQueueFull];
TempStream << "\nGROUP - Static restrictions on the dispatch group: " TempStream << "\nGROUP - Static restrictions on the dispatch group: "
<< DGStalls; << HWStalls[HWStallEvent::DispatchGroupStall];
TempStream << '\n'; TempStream << '\n';
TempStream.flush(); TempStream.flush();
OS << Buffer; OS << Buffer;

View File

@ -59,6 +59,7 @@
#include "Backend.h" #include "Backend.h"
#include "View.h" #include "View.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include <map> #include <map>
@ -80,6 +81,10 @@ class BackendStatistics : public View {
unsigned NumRetired; unsigned NumRetired;
unsigned NumCycles; unsigned NumCycles;
// Counts dispatch stall events caused by unavailability of resources. There
// is one counter for every generic stall kind (see class HWStallEvent).
llvm::SmallVector<unsigned, 8> HWStalls;
void updateHistograms() { void updateHistograms() {
DispatchGroupSizePerCycle[NumDispatched]++; DispatchGroupSizePerCycle[NumDispatched]++;
IssuedPerCycle[NumIssued]++; IssuedPerCycle[NumIssued]++;
@ -93,10 +98,7 @@ class BackendStatistics : public View {
void printDispatchUnitStatistics(llvm::raw_ostream &OS) const; void printDispatchUnitStatistics(llvm::raw_ostream &OS) const;
void printSchedulerStatistics(llvm::raw_ostream &OS) const; void printSchedulerStatistics(llvm::raw_ostream &OS) const;
void printDispatchStalls(llvm::raw_ostream &OS, unsigned RATStalls, void printDispatchStalls(llvm::raw_ostream &OS) const;
unsigned RCUStalls, unsigned SQStalls,
unsigned LDQStalls, unsigned STQStalls,
unsigned DGStalls) const;
void printRATStatistics(llvm::raw_ostream &OS, unsigned Mappings, void printRATStatistics(llvm::raw_ostream &OS, unsigned Mappings,
unsigned MaxUsedMappings) const; unsigned MaxUsedMappings) const;
void printRCUStatistics(llvm::raw_ostream &OS, const Histogram &Histogram, void printRCUStatistics(llvm::raw_ostream &OS, const Histogram &Histogram,
@ -111,7 +113,7 @@ class BackendStatistics : public View {
public: public:
BackendStatistics(const Backend &backend, const llvm::MCSubtargetInfo &sti) BackendStatistics(const Backend &backend, const llvm::MCSubtargetInfo &sti)
: B(backend), STI(sti), NumDispatched(0), NumIssued(0), NumRetired(0), : B(backend), STI(sti), NumDispatched(0), NumIssued(0), NumRetired(0),
NumCycles(0) {} NumCycles(0), HWStalls(HWStallEvent::LastGenericEvent) {}
void onInstructionEvent(const HWInstructionEvent &Event) override; void onInstructionEvent(const HWInstructionEvent &Event) override;
@ -119,10 +121,13 @@ public:
void onCycleEnd(unsigned Cycle) override { updateHistograms(); } void onCycleEnd(unsigned Cycle) override { updateHistograms(); }
void onStallEvent(const HWStallEvent &Event) override {
if (Event.Type < HWStallEvent::LastGenericEvent)
HWStalls[Event.Type]++;
}
void printView(llvm::raw_ostream &OS) const override { void printView(llvm::raw_ostream &OS) const override {
printDispatchStalls(OS, B.getNumRATStalls(), B.getNumRCUStalls(), printDispatchStalls(OS);
B.getNumSQStalls(), B.getNumLDQStalls(),
B.getNumSTQStalls(), B.getNumDispatchGroupStalls());
printRATStatistics(OS, B.getTotalRegisterMappingsCreated(), printRATStatistics(OS, B.getTotalRegisterMappingsCreated(),
B.getMaxUsedRegisterMappings()); B.getMaxUsedRegisterMappings());
printDispatchUnitStatistics(OS); printDispatchUnitStatistics(OS);

View File

@ -280,56 +280,50 @@ void RetireControlUnit::dump() const {
} }
#endif #endif
bool DispatchUnit::checkRAT(const Instruction &Instr) { bool DispatchUnit::checkRAT(unsigned Index, const Instruction &Instr) {
// Collect register definitions from the WriteStates. const InstrDesc &Desc = Instr.getDesc();
SmallVector<unsigned, 8> RegDefs; unsigned NumWrites = Desc.Writes.size();
unsigned RegisterMask = RAT->isAvailable(NumWrites);
for (const std::unique_ptr<WriteState> &Def : Instr.getDefs())
RegDefs.push_back(Def->getRegisterID());
unsigned RegisterMask = RAT->isAvailable(RegDefs);
// A mask with all zeroes means: register files are available. // A mask with all zeroes means: register files are available.
if (RegisterMask) { if (RegisterMask) {
// TODO: We currently implement a single hardware counter for all the Owner->notifyStallEvent(
// dispatch stalls caused by the unavailability of registers in one of the HWStallEvent(HWStallEvent::RegisterFileStall, Index));
// register files. In future, we want to let register files directly notify
// hardware listeners in the event of a dispatch stall. This would simplify
// the logic in Dispatch.[h/cpp], and move all the "hardware counting logic"
// into a View (for example: BackendStatistics).
DispatchStalls[DS_RAT_REG_UNAVAILABLE]++;
return false; return false;
} }
return true; return true;
} }
bool DispatchUnit::checkRCU(const InstrDesc &Desc) { bool DispatchUnit::checkRCU(unsigned Index, const InstrDesc &Desc) {
unsigned NumMicroOps = Desc.NumMicroOps; unsigned NumMicroOps = Desc.NumMicroOps;
if (RCU->isAvailable(NumMicroOps)) if (RCU->isAvailable(NumMicroOps))
return true; return true;
DispatchStalls[DS_RCU_TOKEN_UNAVAILABLE]++; Owner->notifyStallEvent(
HWStallEvent(HWStallEvent::RetireControlUnitStall, Index));
return false; return false;
} }
bool DispatchUnit::checkScheduler(const InstrDesc &Desc) { bool DispatchUnit::checkScheduler(unsigned Index, const InstrDesc &Desc) {
// If this is a zero-latency instruction, then it bypasses // If this is a zero-latency instruction, then it bypasses
// the scheduler. // the scheduler.
HWStallEvent::GenericEventType Type = HWStallEvent::Invalid;
switch (SC->canBeDispatched(Desc)) { switch (SC->canBeDispatched(Desc)) {
case Scheduler::HWS_AVAILABLE: case Scheduler::HWS_AVAILABLE:
return true; return true;
case Scheduler::HWS_QUEUE_UNAVAILABLE: case Scheduler::HWS_QUEUE_UNAVAILABLE:
DispatchStalls[DS_SQ_TOKEN_UNAVAILABLE]++; Type = HWStallEvent::SchedulerQueueFull;
break; break;
case Scheduler::HWS_LD_QUEUE_UNAVAILABLE: case Scheduler::HWS_LD_QUEUE_UNAVAILABLE:
DispatchStalls[DS_LDQ_TOKEN_UNAVAILABLE]++; Type = HWStallEvent::LoadQueueFull;
break; break;
case Scheduler::HWS_ST_QUEUE_UNAVAILABLE: case Scheduler::HWS_ST_QUEUE_UNAVAILABLE:
DispatchStalls[DS_STQ_TOKEN_UNAVAILABLE]++; Type = HWStallEvent::StoreQueueFull;
break; break;
case Scheduler::HWS_DISPATCH_GROUP_RESTRICTION: case Scheduler::HWS_DISPATCH_GROUP_RESTRICTION:
DispatchStalls[DS_DISPATCH_GROUP_RESTRICTION]++; Type = HWStallEvent::DispatchGroupStall;
} }
Owner->notifyStallEvent(HWStallEvent(Type, Index));
return false; return false;
} }
@ -399,16 +393,6 @@ unsigned DispatchUnit::dispatch(unsigned IID, Instruction *NewInst,
void DispatchUnit::dump() const { void DispatchUnit::dump() const {
RAT->dump(); RAT->dump();
RCU->dump(); RCU->dump();
unsigned DSRAT = DispatchStalls[DS_RAT_REG_UNAVAILABLE];
unsigned DSRCU = DispatchStalls[DS_RCU_TOKEN_UNAVAILABLE];
unsigned DSSCHEDQ = DispatchStalls[DS_SQ_TOKEN_UNAVAILABLE];
unsigned DSLQ = DispatchStalls[DS_LDQ_TOKEN_UNAVAILABLE];
unsigned DSSQ = DispatchStalls[DS_STQ_TOKEN_UNAVAILABLE];
dbgs() << "STALLS --- RAT: " << DSRAT << ", RCU: " << DSRCU
<< ", SCHED_QUEUE: " << DSSCHEDQ << ", LOAD_QUEUE: " << DSLQ
<< ", STORE_QUEUE: " << DSSQ << '\n';
} }
#endif #endif

View File

@ -255,41 +255,9 @@ class DispatchUnit {
std::unique_ptr<RetireControlUnit> RCU; std::unique_ptr<RetireControlUnit> RCU;
Backend *Owner; Backend *Owner;
/// Dispatch stall event identifiers. bool checkRAT(unsigned Index, const Instruction &Desc);
/// bool checkRCU(unsigned Index, const InstrDesc &Desc);
/// The naming convention is: bool checkScheduler(unsigned Index, const InstrDesc &Desc);
/// * Event names starts with the "DS_" prefix
/// * For dynamic dispatch stalls, the "DS_" prefix is followed by the
/// the unavailable resource/functional unit acronym (example: RAT)
/// * The last substring is the event reason (example: REG_UNAVAILABLE means
/// that register renaming couldn't find enough spare registers in the
/// register file).
///
/// List of acronyms used for processor resoures:
/// RAT - Register Alias Table (used by the register renaming logic)
/// RCU - Retire Control Unit
/// SQ - Scheduler's Queue
/// LDQ - Load Queue
/// STQ - Store Queue
enum {
DS_RAT_REG_UNAVAILABLE,
DS_RCU_TOKEN_UNAVAILABLE,
DS_SQ_TOKEN_UNAVAILABLE,
DS_LDQ_TOKEN_UNAVAILABLE,
DS_STQ_TOKEN_UNAVAILABLE,
DS_DISPATCH_GROUP_RESTRICTION,
DS_LAST
};
// The DispatchUnit track dispatch stall events caused by unavailable
// of hardware resources. Events are classified based on the stall kind;
// so we have a counter for every source of dispatch stall. Counters are
// stored into a vector `DispatchStall` which is always of size DS_LAST.
std::vector<unsigned> DispatchStalls;
bool checkRAT(const Instruction &Desc);
bool checkRCU(const InstrDesc &Desc);
bool checkScheduler(const InstrDesc &Desc);
void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI); void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI);
void notifyInstructionDispatched(unsigned IID); void notifyInstructionDispatched(unsigned IID);
@ -304,7 +272,7 @@ public:
RAT(llvm::make_unique<RegisterFile>(MRI, RegisterFileSize)), RAT(llvm::make_unique<RegisterFile>(MRI, RegisterFileSize)),
RCU(llvm::make_unique<RetireControlUnit>(MicroOpBufferSize, RCU(llvm::make_unique<RetireControlUnit>(MicroOpBufferSize,
MaxRetirePerCycle, this)), MaxRetirePerCycle, this)),
Owner(B), DispatchStalls(DS_LAST, 0) {} Owner(B) {}
unsigned getDispatchWidth() const { return DispatchWidth; } unsigned getDispatchWidth() const { return DispatchWidth; }
@ -314,10 +282,11 @@ public:
bool isRCUEmpty() const { return RCU->isEmpty(); } bool isRCUEmpty() const { return RCU->isEmpty(); }
bool canDispatch(const Instruction &Inst) { bool canDispatch(unsigned Index, const Instruction &Inst) {
const InstrDesc &Desc = Inst.getDesc(); const InstrDesc &Desc = Inst.getDesc();
assert(isAvailable(Desc.NumMicroOps)); assert(isAvailable(Desc.NumMicroOps));
return checkRCU(Desc) && checkRAT(Inst) && checkScheduler(Desc); return checkRCU(Index, Desc) && checkRAT(Index, Inst) &&
checkScheduler(Index, Desc);
} }
unsigned dispatch(unsigned IID, Instruction *NewInst, unsigned dispatch(unsigned IID, Instruction *NewInst,
@ -327,24 +296,6 @@ public:
unsigned RegID) const { unsigned RegID) const {
return RAT->collectWrites(Vec, RegID); return RAT->collectWrites(Vec, RegID);
} }
unsigned getNumRATStalls() const {
return DispatchStalls[DS_RAT_REG_UNAVAILABLE];
}
unsigned getNumRCUStalls() const {
return DispatchStalls[DS_RCU_TOKEN_UNAVAILABLE];
}
unsigned getNumSQStalls() const {
return DispatchStalls[DS_SQ_TOKEN_UNAVAILABLE];
}
unsigned getNumLDQStalls() const {
return DispatchStalls[DS_LDQ_TOKEN_UNAVAILABLE];
}
unsigned getNumSTQStalls() const {
return DispatchStalls[DS_STQ_TOKEN_UNAVAILABLE];
}
unsigned getNumDispatchGroupStalls() const {
return DispatchStalls[DS_DISPATCH_GROUP_RESTRICTION];
}
unsigned getMaxUsedRegisterMappings(unsigned RegFileIndex = 0) const { unsigned getMaxUsedRegisterMappings(unsigned RegFileIndex = 0) const {
return RAT->getMaxUsedRegisterMappings(RegFileIndex); return RAT->getMaxUsedRegisterMappings(RegFileIndex);
} }
@ -362,6 +313,8 @@ public:
void notifyInstructionRetired(unsigned Index); void notifyInstructionRetired(unsigned Index);
void notifyDispatchStall(unsigned Index, unsigned EventType);
void onInstructionExecuted(unsigned TokenID) { void onInstructionExecuted(unsigned TokenID) {
RCU->onInstructionExecuted(TokenID); RCU->onInstructionExecuted(TokenID);
} }

View File

@ -68,6 +68,30 @@ public:
const llvm::ArrayRef<std::pair<ResourceRef, unsigned>> UsedResources; const llvm::ArrayRef<std::pair<ResourceRef, unsigned>> UsedResources;
}; };
// A HWStallEvent represents a pipeline stall caused by the lack of hardware
// resources.
class HWStallEvent {
public:
enum GenericEventType {
Invalid = 0,
// Generic stall events generated by the DispatchUnit.
RegisterFileStall,
RetireControlUnitStall,
DispatchGroupStall,
SchedulerQueueFull,
LoadQueueFull,
StoreQueueFull,
LastGenericEvent
};
HWStallEvent(unsigned type, unsigned index) : Type(type), Index(index) {}
// The exact meaning of the stall event type depends on the subtarget.
const unsigned Type;
// The index of the instruction in the source manager.
const unsigned Index;
};
class HWEventListener { class HWEventListener {
public: public:
// Generic events generated by the backend pipeline. // Generic events generated by the backend pipeline.
@ -75,6 +99,7 @@ public:
virtual void onCycleEnd(unsigned Cycle) {} virtual void onCycleEnd(unsigned Cycle) {}
virtual void onInstructionEvent(const HWInstructionEvent &Event) {} virtual void onInstructionEvent(const HWInstructionEvent &Event) {}
virtual void onStallEvent(const HWStallEvent &Event) {}
using ResourceRef = std::pair<uint64_t, uint64_t>; using ResourceRef = std::pair<uint64_t, uint64_t>;
virtual void onResourceAvailable(const ResourceRef &RRef) {} virtual void onResourceAvailable(const ResourceRef &RRef) {}