1
0
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:
Clement Courbet 2018-03-13 13:11:01 +00:00
parent 56164e7cbd
commit 767a644ff6
12 changed files with 164 additions and 139 deletions

View File

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

View File

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

View File

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

View File

@ -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++; }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 {

View File

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