mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[llvm-mca] Refactor event listeners to make the backend agnostic to event types.
Summary: This is a first step towards making the pipeline configurable. Subscribers: llvm-commits, andreadb Differential Revision: https://reviews.llvm.org/D44309 llvm-svn: 327389
This commit is contained in:
parent
56164e7cbd
commit
767a644ff6
@ -65,50 +65,9 @@ void Backend::notifyCycleBegin(unsigned Cycle) {
|
||||
HWS->cycleEvent(Cycle);
|
||||
}
|
||||
|
||||
void Backend::notifyInstructionDispatched(unsigned Index) {
|
||||
DEBUG(dbgs() << "[E] Instruction Dispatched: " << Index << '\n');
|
||||
void Backend::notifyInstructionEvent(const HWInstructionEvent &Event) {
|
||||
for (HWEventListener *Listener : Listeners)
|
||||
Listener->onInstructionDispatched(Index);
|
||||
}
|
||||
|
||||
void Backend::notifyInstructionReady(unsigned Index) {
|
||||
DEBUG(dbgs() << "[E] Instruction Ready: " << Index << '\n');
|
||||
for (HWEventListener *Listener : Listeners)
|
||||
Listener->onInstructionReady(Index);
|
||||
}
|
||||
|
||||
void Backend::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';
|
||||
}
|
||||
);
|
||||
|
||||
for (HWEventListener *Listener : Listeners)
|
||||
Listener->onInstructionIssued(Index, Used);
|
||||
}
|
||||
|
||||
void Backend::notifyInstructionExecuted(unsigned Index) {
|
||||
DEBUG(dbgs() << "[E] Instruction Executed: " << Index << '\n');
|
||||
for (HWEventListener *Listener : Listeners)
|
||||
Listener->onInstructionExecuted(Index);
|
||||
|
||||
const Instruction &IS = *Instructions[Index];
|
||||
DU->onInstructionExecuted(IS.getRCUTokenID());
|
||||
}
|
||||
|
||||
void Backend::notifyInstructionRetired(unsigned Index) {
|
||||
DEBUG(dbgs() << "[E] Instruction Retired: " << Index << '\n');
|
||||
for (HWEventListener *Listener : Listeners)
|
||||
Listener->onInstructionRetired(Index);
|
||||
|
||||
const Instruction &IS = *Instructions[Index];
|
||||
DU->invalidateRegisterMappings(IS);
|
||||
Instructions.erase(Index);
|
||||
Listener->onInstructionEvent(Event);
|
||||
}
|
||||
|
||||
void Backend::notifyResourceAvailable(const ResourceRef &RR) {
|
||||
|
@ -23,6 +23,7 @@
|
||||
namespace mca {
|
||||
|
||||
class HWEventListener;
|
||||
class HWInstructionEvent;
|
||||
|
||||
/// \brief An out of order backend for a specific subtarget.
|
||||
///
|
||||
@ -71,6 +72,7 @@ public:
|
||||
RegisterFileSize, MaxRetirePerCycle, DispatchWidth, HWS.get())),
|
||||
SM(Source), Cycles(0) {
|
||||
IB = llvm::make_unique<InstrBuilder>(MCII, HWS->getProcResourceMasks());
|
||||
HWS->setDispatchUnit(DU.get());
|
||||
}
|
||||
|
||||
void run() {
|
||||
@ -80,6 +82,13 @@ public:
|
||||
|
||||
unsigned getNumIterations() const { return SM.getNumIterations(); }
|
||||
unsigned getNumInstructions() const { return SM.size(); }
|
||||
const Instruction &getInstruction(unsigned Index) const {
|
||||
const auto It = Instructions.find(Index);
|
||||
assert(It != Instructions.end() && "no running instructions with index");
|
||||
assert(It->second);
|
||||
return *Instructions.find(Index)->second;
|
||||
}
|
||||
void eraseInstruction(unsigned Index) { Instructions.erase(Index); }
|
||||
unsigned getNumCycles() const { return Cycles; }
|
||||
unsigned getTotalRegisterMappingsCreated() const {
|
||||
return DU->getTotalRegisterMappingsCreated();
|
||||
@ -122,14 +131,8 @@ public:
|
||||
|
||||
void addEventListener(HWEventListener *Listener);
|
||||
void notifyCycleBegin(unsigned Cycle);
|
||||
void notifyInstructionDispatched(unsigned Index);
|
||||
void notifyInstructionReady(unsigned Index);
|
||||
void notifyInstructionIssued(
|
||||
unsigned Index,
|
||||
const llvm::ArrayRef<std::pair<ResourceRef, unsigned>> &Used);
|
||||
void notifyInstructionExecuted(unsigned Index);
|
||||
void notifyInstructionEvent(const HWInstructionEvent &Event);
|
||||
void notifyResourceAvailable(const ResourceRef &RR);
|
||||
void notifyInstructionRetired(unsigned Index);
|
||||
void notifyCycleEnd(unsigned Cycle);
|
||||
};
|
||||
|
||||
|
@ -20,6 +20,22 @@ using namespace llvm;
|
||||
|
||||
namespace mca {
|
||||
|
||||
void BackendStatistics::onInstructionEvent(const HWInstructionEvent &Event) {
|
||||
switch (Event.Type) {
|
||||
case HWInstructionEvent::Retired:
|
||||
++NumRetired;
|
||||
break;
|
||||
case HWInstructionEvent::Issued:
|
||||
++NumIssued;
|
||||
break;
|
||||
case HWInstructionEvent::Dispatched:
|
||||
++NumDispatched;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BackendStatistics::printRetireUnitStatistics(llvm::raw_ostream &OS) const {
|
||||
std::string Buffer;
|
||||
raw_string_ostream TempStream(Buffer);
|
||||
|
@ -110,14 +110,7 @@ public:
|
||||
BackendStatistics(const Backend &backend)
|
||||
: B(backend), NumDispatched(0), NumIssued(0), NumRetired(0), NumCycles(0) {}
|
||||
|
||||
void onInstructionDispatched(unsigned Index) override { NumDispatched++; }
|
||||
void
|
||||
onInstructionIssued(unsigned Index,
|
||||
const llvm::ArrayRef<std::pair<ResourceRef, unsigned>>
|
||||
& /* unused */) override {
|
||||
NumIssued++;
|
||||
}
|
||||
void onInstructionRetired(unsigned Index) override { NumRetired++; }
|
||||
void onInstructionEvent(const HWInstructionEvent &Event) override;
|
||||
|
||||
void onCycleBegin(unsigned Cycle) override { NumCycles++; }
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "Dispatch.h"
|
||||
#include "Backend.h"
|
||||
#include "HWEventListener.h"
|
||||
#include "Scheduler.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
|
||||
@ -150,11 +151,19 @@ unsigned RetireControlUnit::reserveSlot(unsigned Index, unsigned NumMicroOps) {
|
||||
}
|
||||
|
||||
void DispatchUnit::notifyInstructionDispatched(unsigned Index) {
|
||||
Owner->notifyInstructionDispatched(Index);
|
||||
DEBUG(dbgs() << "[E] Instruction Dispatched: " << Index << '\n');
|
||||
Owner->notifyInstructionEvent(
|
||||
HWInstructionEvent(HWInstructionEvent::Dispatched, Index));
|
||||
}
|
||||
|
||||
void DispatchUnit::notifyInstructionRetired(unsigned Index) {
|
||||
Owner->notifyInstructionRetired(Index);
|
||||
DEBUG(dbgs() << "[E] Instruction Retired: " << Index << '\n');
|
||||
Owner->notifyInstructionEvent(
|
||||
HWInstructionEvent(HWInstructionEvent::Retired, Index));
|
||||
|
||||
const Instruction &IS = Owner->getInstruction(Index);
|
||||
invalidateRegisterMappings(IS);
|
||||
Owner->eraseInstruction(Index);
|
||||
}
|
||||
|
||||
void RetireControlUnit::cycleEvent() {
|
||||
@ -243,7 +252,7 @@ unsigned DispatchUnit::dispatch(unsigned IID, Instruction *NewInst) {
|
||||
// Reserve slots in the RCU.
|
||||
unsigned RCUTokenID = RCU->reserveSlot(IID, NumMicroOps);
|
||||
NewInst->setRCUTokenID(RCUTokenID);
|
||||
Owner->notifyInstructionDispatched(IID);
|
||||
notifyInstructionDispatched(IID);
|
||||
|
||||
SC->scheduleInstruction(IID, NewInst);
|
||||
return RCUTokenID;
|
||||
|
@ -21,28 +21,67 @@
|
||||
|
||||
namespace mca {
|
||||
|
||||
// An HWInstructionEvent represents state changes of instructions that
|
||||
// listeners might be interested in. Listeners can choose to ignore any event
|
||||
// they are not interested in.
|
||||
class HWInstructionEvent {
|
||||
public:
|
||||
// This is the list of event types that are shared by all targets, that
|
||||
// generic subtarget-agnostic classes (e.g. Backend, HWInstructionEvent, ...)
|
||||
// and generic Views can manipulate.
|
||||
// Subtargets are free to define additional event types, that are goin to be
|
||||
// handled by generic components as opaque values, but can still be
|
||||
// emitted by subtarget-specific pipeline components (e.g. Scheduler,
|
||||
// DispatchUnit, ...) and interpreted by subtarget-specific EventListener
|
||||
// implementations.
|
||||
enum GenericEventType {
|
||||
Invalid = 0,
|
||||
// Events generated by the Retire Control Unit.
|
||||
Retired,
|
||||
// Events generated by the Scheduler.
|
||||
Ready,
|
||||
Issued,
|
||||
Executed,
|
||||
// Events generated by the Dispatch logic.
|
||||
Dispatched,
|
||||
|
||||
LastGenericEventType,
|
||||
};
|
||||
|
||||
HWInstructionEvent(unsigned Type, unsigned Index)
|
||||
: Type(Type), Index(Index) {}
|
||||
|
||||
// The event type. The exact meaning depends on the subtarget.
|
||||
const unsigned Type;
|
||||
// The index of the instruction in the source manager.
|
||||
const unsigned Index;
|
||||
};
|
||||
|
||||
class HWInstructionIssuedEvent : public HWInstructionEvent {
|
||||
public:
|
||||
using ResourceRef = std::pair<uint64_t, uint64_t>;
|
||||
HWInstructionIssuedEvent(
|
||||
unsigned Index, const llvm::ArrayRef<std::pair<ResourceRef, unsigned>> UR)
|
||||
: HWInstructionEvent(HWInstructionEvent::Issued, Index),
|
||||
UsedResources(UR) {}
|
||||
|
||||
const llvm::ArrayRef<std::pair<ResourceRef, unsigned>> UsedResources;
|
||||
};
|
||||
|
||||
class HWEventListener {
|
||||
public:
|
||||
// Events generated by the Retire Control Unit.
|
||||
virtual void onInstructionRetired(unsigned Index) {};
|
||||
|
||||
// Events generated by the Scheduler.
|
||||
using ResourceRef = std::pair<uint64_t, uint64_t>;
|
||||
virtual void
|
||||
onInstructionIssued(unsigned Index,
|
||||
const llvm::ArrayRef<std::pair<ResourceRef, unsigned>> &Used) {}
|
||||
virtual void onInstructionExecuted(unsigned Index) {}
|
||||
virtual void onInstructionReady(unsigned Index) {}
|
||||
virtual void onResourceAvailable(const ResourceRef &RRef) {};
|
||||
|
||||
// Events generated by the Dispatch logic.
|
||||
virtual void onInstructionDispatched(unsigned Index) {}
|
||||
|
||||
// Generic events generated by the Backend.
|
||||
// Generic events generated by the backend pipeline.
|
||||
virtual void onCycleBegin(unsigned Cycle) {}
|
||||
virtual void onCycleEnd(unsigned Cycle) {}
|
||||
|
||||
virtual ~HWEventListener() = default;
|
||||
virtual void onInstructionEvent(const HWInstructionEvent &Event) {}
|
||||
|
||||
using ResourceRef = std::pair<uint64_t, uint64_t>;
|
||||
virtual void onResourceAvailable(const ResourceRef &RRef) {}
|
||||
|
||||
virtual ~HWEventListener() {}
|
||||
|
||||
private:
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
|
@ -39,10 +39,13 @@ void ResourcePressureView::initialize() {
|
||||
std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0);
|
||||
}
|
||||
|
||||
void ResourcePressureView::onInstructionIssued(
|
||||
unsigned Index, const ArrayRef<std::pair<ResourceRef, unsigned>> &Used) {
|
||||
unsigned SourceIdx = Index % Source.size();
|
||||
for (const std::pair<ResourceRef, unsigned> &Use : Used) {
|
||||
void ResourcePressureView::onInstructionEvent(const HWInstructionEvent &Event) {
|
||||
// We're only interested in Issue events.
|
||||
if (Event.Type != HWInstructionEvent::Issued)
|
||||
return;
|
||||
const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event);
|
||||
unsigned SourceIdx = Event.Index % Source.size();
|
||||
for (const std::pair<ResourceRef, unsigned> &Use : IssueEvent.UsedResources) {
|
||||
const ResourceRef &RR = Use.first;
|
||||
assert(Resource2VecIndex.find(RR.first) != Resource2VecIndex.end());
|
||||
unsigned R2VIndex = Resource2VecIndex[RR.first];
|
||||
|
@ -96,9 +96,7 @@ public:
|
||||
initialize();
|
||||
}
|
||||
|
||||
void onInstructionIssued(
|
||||
unsigned Index,
|
||||
const llvm::ArrayRef<std::pair<ResourceRef, unsigned>> &Used) override;
|
||||
void onInstructionEvent(const HWInstructionEvent &Event) override;
|
||||
|
||||
void printView(llvm::raw_ostream &OS) const override {
|
||||
unsigned Executions = Source.getNumIterations();
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "Scheduler.h"
|
||||
#include "Backend.h"
|
||||
#include "HWEventListener.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
@ -445,16 +446,30 @@ void Scheduler::updateIssuedQueue() {
|
||||
|
||||
void Scheduler::notifyInstructionIssued(
|
||||
unsigned Index, const ArrayRef<std::pair<ResourceRef, unsigned>> &Used) {
|
||||
Owner->notifyInstructionIssued(Index, 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';
|
||||
});
|
||||
Owner->notifyInstructionEvent(HWInstructionIssuedEvent(Index, Used));
|
||||
}
|
||||
|
||||
void Scheduler::notifyInstructionExecuted(unsigned Index) {
|
||||
LSU->onInstructionExecuted(Index);
|
||||
Owner->notifyInstructionExecuted(Index);
|
||||
DEBUG(dbgs() << "[E] Instruction Executed: " << Index << '\n');
|
||||
Owner->notifyInstructionEvent(
|
||||
HWInstructionEvent(HWInstructionEvent::Executed, Index));
|
||||
|
||||
const Instruction &IS = Owner->getInstruction(Index);
|
||||
DU->onInstructionExecuted(IS.getRCUTokenID());
|
||||
}
|
||||
|
||||
void Scheduler::notifyInstructionReady(unsigned Index) {
|
||||
Owner->notifyInstructionReady(Index);
|
||||
DEBUG(dbgs() << "[E] Instruction Ready: " << Index << '\n');
|
||||
Owner->notifyInstructionEvent(
|
||||
HWInstructionEvent(HWInstructionEvent::Ready, Index));
|
||||
}
|
||||
|
||||
void Scheduler::notifyResourceAvailable(const ResourceRef &RR) {
|
||||
|
@ -24,6 +24,8 @@
|
||||
namespace mca {
|
||||
|
||||
class Backend;
|
||||
class DispatchUnit;
|
||||
|
||||
/// Used to notify the internal state of a processor resource.
|
||||
///
|
||||
/// A processor resource is available if it is not reserved, and there are
|
||||
@ -455,7 +457,10 @@ class Scheduler {
|
||||
std::unique_ptr<LSUnit> LSU;
|
||||
|
||||
// The Backend gets notified when instructions are ready/issued/executed.
|
||||
Backend *Owner;
|
||||
Backend *const Owner;
|
||||
|
||||
// The dispatch unit gets notified when instructions are executed.
|
||||
DispatchUnit *DU;
|
||||
|
||||
using QueueEntryTy = std::pair<unsigned, Instruction *>;
|
||||
std::map<unsigned, Instruction *> WaitQueue;
|
||||
@ -486,6 +491,8 @@ public:
|
||||
AssumeNoAlias)),
|
||||
Owner(B) {}
|
||||
|
||||
void setDispatchUnit(DispatchUnit *DispUnit) { DU = DispUnit; }
|
||||
|
||||
/// Scheduling events.
|
||||
///
|
||||
/// The DispatchUnit is responsible for querying the Scheduler before
|
||||
|
@ -34,55 +34,44 @@ void TimelineView::initialize(unsigned MaxIterations) {
|
||||
std::fill(WaitTime.begin(), WaitTime.end(), NullWTEntry);
|
||||
}
|
||||
|
||||
void TimelineView::onInstructionDispatched(unsigned Index) {
|
||||
if (CurrentCycle >= MaxCycle || Index >= Timeline.size())
|
||||
void TimelineView::onInstructionEvent(const HWInstructionEvent &Event) {
|
||||
if (CurrentCycle >= MaxCycle || Event.Index >= Timeline.size())
|
||||
return;
|
||||
Timeline[Index].CycleDispatched = CurrentCycle;
|
||||
LastCycle = std::max(LastCycle, CurrentCycle);
|
||||
}
|
||||
switch (Event.Type) {
|
||||
case HWInstructionEvent::Retired: {
|
||||
TimelineViewEntry &TVEntry = Timeline[Event.Index];
|
||||
TVEntry.CycleRetired = CurrentCycle;
|
||||
|
||||
void TimelineView::onInstructionReady(unsigned Index) {
|
||||
if (CurrentCycle >= MaxCycle || Index >= Timeline.size())
|
||||
// Update the WaitTime entry which corresponds to this Index.
|
||||
WaitTimeEntry &WTEntry = WaitTime[Event.Index % AsmSequence.size()];
|
||||
WTEntry.Executions++;
|
||||
WTEntry.CyclesSpentInSchedulerQueue +=
|
||||
TVEntry.CycleIssued - TVEntry.CycleDispatched;
|
||||
assert(TVEntry.CycleDispatched <= TVEntry.CycleReady);
|
||||
WTEntry.CyclesSpentInSQWhileReady +=
|
||||
TVEntry.CycleIssued - TVEntry.CycleReady;
|
||||
WTEntry.CyclesSpentAfterWBAndBeforeRetire +=
|
||||
(TVEntry.CycleRetired - 1) - TVEntry.CycleExecuted;
|
||||
break;
|
||||
}
|
||||
case HWInstructionEvent::Ready:
|
||||
Timeline[Event.Index].CycleReady = CurrentCycle;
|
||||
break;
|
||||
case HWInstructionEvent::Issued:
|
||||
Timeline[Event.Index].CycleIssued = CurrentCycle;
|
||||
break;
|
||||
case HWInstructionEvent::Executed:
|
||||
Timeline[Event.Index].CycleExecuted = CurrentCycle;
|
||||
break;
|
||||
case HWInstructionEvent::Dispatched:
|
||||
Timeline[Event.Index].CycleDispatched = CurrentCycle;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
Timeline[Index].CycleReady = CurrentCycle;
|
||||
}
|
||||
LastCycle = std::max(LastCycle, CurrentCycle);
|
||||
}
|
||||
|
||||
void TimelineView::onInstructionIssued(
|
||||
unsigned Index,
|
||||
const ArrayRef<std::pair<ResourceRef, unsigned>> & /* Unused */) {
|
||||
if (CurrentCycle >= MaxCycle || Index >= Timeline.size())
|
||||
return;
|
||||
Timeline[Index].CycleIssued = CurrentCycle;
|
||||
LastCycle = std::max(LastCycle, CurrentCycle);
|
||||
}
|
||||
|
||||
void TimelineView::onInstructionExecuted(unsigned Index) {
|
||||
if (CurrentCycle >= MaxCycle || Index >= Timeline.size())
|
||||
return;
|
||||
Timeline[Index].CycleExecuted = CurrentCycle;
|
||||
LastCycle = std::max(LastCycle, CurrentCycle);
|
||||
}
|
||||
|
||||
void TimelineView::onInstructionRetired(unsigned Index) {
|
||||
if (CurrentCycle >= MaxCycle || Index >= Timeline.size())
|
||||
return;
|
||||
TimelineViewEntry &TVEntry = Timeline[Index];
|
||||
TVEntry.CycleRetired = CurrentCycle;
|
||||
LastCycle = std::max(LastCycle, CurrentCycle);
|
||||
|
||||
// Update the WaitTime entry which corresponds to this Index.
|
||||
|
||||
WaitTimeEntry &WTEntry = WaitTime[Index % AsmSequence.size()];
|
||||
WTEntry.Executions++;
|
||||
WTEntry.CyclesSpentInSchedulerQueue +=
|
||||
TVEntry.CycleIssued - TVEntry.CycleDispatched;
|
||||
assert(TVEntry.CycleDispatched <= TVEntry.CycleReady);
|
||||
WTEntry.CyclesSpentInSQWhileReady += TVEntry.CycleIssued - TVEntry.CycleReady;
|
||||
WTEntry.CyclesSpentAfterWBAndBeforeRetire +=
|
||||
(TVEntry.CycleRetired - 1) - TVEntry.CycleExecuted;
|
||||
}
|
||||
|
||||
void TimelineView::printWaitTimeEntry(raw_string_ostream &OS,
|
||||
const WaitTimeEntry &Entry,
|
||||
unsigned SourceIndex) const {
|
||||
|
@ -162,14 +162,8 @@ public:
|
||||
void initialize(unsigned MaxIterations);
|
||||
|
||||
// Event handlers.
|
||||
void onInstructionDispatched(unsigned Index) override;
|
||||
void onInstructionReady(unsigned Index) override;
|
||||
void onInstructionIssued(
|
||||
unsigned Index,
|
||||
const llvm::ArrayRef<std::pair<ResourceRef, unsigned>> &Used) override;
|
||||
void onInstructionExecuted(unsigned Index) override;
|
||||
void onInstructionRetired(unsigned Index) override;
|
||||
void onCycleBegin(unsigned Cycle) override { CurrentCycle = Cycle; }
|
||||
void onInstructionEvent(const HWInstructionEvent &Event) override;
|
||||
|
||||
// print functionalities.
|
||||
void printTimeline(llvm::raw_ostream &OS) const;
|
||||
|
Loading…
x
Reference in New Issue
Block a user