)
add_llvm_tool(llvm-mca
- Backend.cpp
- BackendPrinter.cpp
CodeRegion.cpp
DispatchStage.cpp
DispatchStatistics.cpp
InstructionTables.cpp
LSUnit.cpp
llvm-mca.cpp
+ Pipeline.cpp
+ PipelinePrinter.cpp
RegisterFile.cpp
RegisterFileStatistics.cpp
ResourcePressureView.cpp
//===----------------------------------------------------------------------===//
#include "DispatchStage.h"
-#include "Backend.h"
#include "HWEventListener.h"
+#include "Pipeline.h"
#include "Scheduler.h"
#include "llvm/Support/Debug.h"
class WriteState;
class Scheduler;
-class Backend;
+class Pipeline;
// Implements the hardware dispatch logic.
//
unsigned DispatchWidth;
unsigned AvailableEntries;
unsigned CarryOver;
- Backend *Owner;
+ Pipeline *Owner;
const llvm::MCSubtargetInfo &STI;
RetireControlUnit &RCU;
RegisterFile &PRF;
}
public:
- DispatchStage(Backend *B, const llvm::MCSubtargetInfo &Subtarget,
+ DispatchStage(Pipeline *P, const llvm::MCSubtargetInfo &Subtarget,
const llvm::MCRegisterInfo &MRI, unsigned RegisterFileSize,
unsigned MaxDispatchWidth, RetireControlUnit &R,
RegisterFile &F, Scheduler &Sched)
: DispatchWidth(MaxDispatchWidth), AvailableEntries(MaxDispatchWidth),
- CarryOver(0U), Owner(B), STI(Subtarget), RCU(R), PRF(F), SC(Sched) {}
+ CarryOver(0U), Owner(P), STI(Subtarget), RCU(R), PRF(F), SC(Sched) {}
// We can always try to dispatch, so returning false is okay in this case.
// The retire stage, which controls the RCU, might have items to complete but
//===----------------------------------------------------------------------===//
#include "ExecuteStage.h"
-#include "Backend.h"
+#include "Pipeline.h"
#include "Scheduler.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Debug.h"
namespace mca {
-class Backend;
+class Pipeline;
class ExecuteStage : public Stage {
// Owner will go away when we move listeners/eventing to the stages.
- Backend *Owner;
+ Pipeline *Owner;
RetireControlUnit &RCU;
Scheduler &HWS;
void issueReadyInstructions();
public:
- ExecuteStage(Backend *B, RetireControlUnit &R, Scheduler &S)
- : Stage(), Owner(B), RCU(R), HWS(S) {}
+ ExecuteStage(Pipeline *P, RetireControlUnit &R, Scheduler &S)
+ : Stage(), Owner(P), RCU(R), HWS(S) {}
ExecuteStage(const ExecuteStage &Other) = delete;
ExecuteStage &operator=(const ExecuteStage &Other) = delete;
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.
+ // generic subtarget-agnostic classes (e.g., Pipeline, 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,
+ // emitted by subtarget-specific pipeline stages (e.g., ExecuteStage,
// DispatchStage, ...) and interpreted by subtarget-specific EventListener
// implementations.
enum GenericEventType {
class HWEventListener {
public:
- // Generic events generated by the backend pipeline.
+ // Generic events generated by the pipeline.
virtual void onCycleBegin() {}
virtual void onCycleEnd() {}
//
//===----------------------------------------------------------------------===//
//
-// This file defines abstractions used by the Backend to model register reads,
+// This file defines abstractions used by the Pipeline to model register reads,
// register writes and instructions.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
/// \file
///
-/// This file defines abstractions used by the Backend to model register reads,
+/// This file defines abstractions used by the Pipeline to model register reads,
/// register writes and instructions.
///
//===----------------------------------------------------------------------===//
bool isZeroLatency() const { return !MaxLatency && Resources.empty(); }
};
-/// An instruction dispatched to the out-of-order backend.
+/// An instruction propagated through the simulated instruction pipeline.
///
-/// This class is used to monitor changes in the internal state of instructions
-/// that are dispatched by the DispatchUnit to the hardware schedulers.
+/// This class is used to monitor changes to the internal state of instructions
+/// that are sent to the various components of the simulated hardware pipeline.
class Instruction {
const InstrDesc &Desc;
/// This file implements method InstructionTables::run().
/// Method run() prints a theoretical resource pressure distribution based on
/// the information available in the scheduling model, and without running
-/// the backend pipeline.
+/// the pipeline.
///
//===----------------------------------------------------------------------===//
-//===--------------------- Backend.cpp --------------------------*- C++ -*-===//
+//===--------------------- Pipeline.cpp -------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
//===----------------------------------------------------------------------===//
/// \file
///
-/// Implementation of class Backend which emulates an hardware OoO backend.
+/// This file implements an ordered container of stages that simulate the
+/// pipeline of a hardware backend.
///
//===----------------------------------------------------------------------===//
-#include "Backend.h"
+#include "Pipeline.h"
#include "HWEventListener.h"
#include "llvm/CodeGen/TargetSchedule.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
-void Backend::addEventListener(HWEventListener *Listener) {
+void Pipeline::addEventListener(HWEventListener *Listener) {
if (Listener)
Listeners.insert(Listener);
}
-bool Backend::hasWorkToProcess() {
+bool Pipeline::hasWorkToProcess() {
const auto It = llvm::find_if(Stages, [](const std::unique_ptr<Stage> &S) {
return S->hasWorkToComplete();
});
// This routine returns early if any stage returns 'false' after execute() is
// called on it.
-bool Backend::executeStages(InstRef &IR) {
+bool Pipeline::executeStages(InstRef &IR) {
for (const std::unique_ptr<Stage> &S : Stages)
if (!S->execute(IR))
return false;
return true;
}
-void Backend::postExecuteStages(const InstRef &IR) {
+void Pipeline::postExecuteStages(const InstRef &IR) {
for (const std::unique_ptr<Stage> &S : Stages)
S->postExecute(IR);
}
-void Backend::run() {
+void Pipeline::run() {
while (hasWorkToProcess())
runCycle(Cycles++);
}
-void Backend::runCycle(unsigned Cycle) {
+void Pipeline::runCycle(unsigned Cycle) {
notifyCycleBegin(Cycle);
// Update the stages before we do any processing for this cycle.
notifyCycleEnd(Cycle);
}
-void Backend::notifyCycleBegin(unsigned Cycle) {
+void Pipeline::notifyCycleBegin(unsigned Cycle) {
LLVM_DEBUG(dbgs() << "[E] Cycle begin: " << Cycle << '\n');
for (HWEventListener *Listener : Listeners)
Listener->onCycleBegin();
}
-void Backend::notifyInstructionEvent(const HWInstructionEvent &Event) {
+void Pipeline::notifyInstructionEvent(const HWInstructionEvent &Event) {
for (HWEventListener *Listener : Listeners)
Listener->onInstructionEvent(Event);
}
-void Backend::notifyStallEvent(const HWStallEvent &Event) {
+void Pipeline::notifyStallEvent(const HWStallEvent &Event) {
for (HWEventListener *Listener : Listeners)
Listener->onStallEvent(Event);
}
-void Backend::notifyResourceAvailable(const ResourceRef &RR) {
+void Pipeline::notifyResourceAvailable(const ResourceRef &RR) {
LLVM_DEBUG(dbgs() << "[E] Resource Available: [" << RR.first << '.'
<< RR.second << "]\n");
for (HWEventListener *Listener : Listeners)
Listener->onResourceAvailable(RR);
}
-void Backend::notifyReservedBuffers(ArrayRef<unsigned> Buffers) {
+void Pipeline::notifyReservedBuffers(ArrayRef<unsigned> Buffers) {
for (HWEventListener *Listener : Listeners)
Listener->onReservedBuffers(Buffers);
}
-void Backend::notifyReleasedBuffers(ArrayRef<unsigned> Buffers) {
+void Pipeline::notifyReleasedBuffers(ArrayRef<unsigned> Buffers) {
for (HWEventListener *Listener : Listeners)
Listener->onReleasedBuffers(Buffers);
}
-void Backend::notifyCycleEnd(unsigned Cycle) {
+void Pipeline::notifyCycleEnd(unsigned Cycle) {
LLVM_DEBUG(dbgs() << "[E] Cycle end: " << Cycle << "\n\n");
for (HWEventListener *Listener : Listeners)
Listener->onCycleEnd();
-//===--------------------- Backend.h ----------------------------*- C++ -*-===//
+//===--------------------- Pipeline.h ---------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
//===----------------------------------------------------------------------===//
/// \file
///
-/// This file implements an OoO backend for the llvm-mca tool.
+/// This file implements an ordered container of stages that simulate the
+/// pipeline of a hardware backend.
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_LLVM_MCA_BACKEND_H
-#define LLVM_TOOLS_LLVM_MCA_BACKEND_H
+#ifndef LLVM_TOOLS_LLVM_MCA_PIPELINE_H
+#define LLVM_TOOLS_LLVM_MCA_PIPELINE_H
#include "Scheduler.h"
#include "Stage.h"
class HWInstructionEvent;
class HWStallEvent;
-/// An out of order backend for a specific subtarget.
+/// A pipeline for a specific subtarget.
///
/// It emulates an out-of-order execution of instructions. Instructions are
/// fetched from a MCInst sequence managed by an initial 'Fetch' stage.
/// is defined by the SourceMgr object, which is managed by the initial stage
/// of the instruction pipeline.
///
-/// The Backend entry point is method 'run()' which executes cycles in a loop
+/// The Pipeline entry point is method 'run()' which executes cycles in a loop
/// until there are new instructions to dispatch, and not every instruction
/// has been retired.
///
-/// Internally, the Backend collects statistical information in the form of
+/// Internally, the Pipeline collects statistical information in the form of
/// histograms. For example, it tracks how the dispatch group size changes
/// over time.
-class Backend {
- /// An ordered list of stages that define this backend's instruction pipeline.
+class Pipeline {
+ /// An ordered list of stages that define this instruction pipeline.
llvm::SmallVector<std::unique_ptr<Stage>, 8> Stages;
std::set<HWEventListener *> Listeners;
unsigned Cycles;
void runCycle(unsigned Cycle);
public:
- Backend(unsigned DispatchWidth = 0, unsigned RegisterFileSize = 0,
- unsigned LoadQueueSize = 0, unsigned StoreQueueSize = 0,
- bool AssumeNoAlias = false)
+ Pipeline(unsigned DispatchWidth = 0, unsigned RegisterFileSize = 0,
+ unsigned LoadQueueSize = 0, unsigned StoreQueueSize = 0,
+ bool AssumeNoAlias = false)
: Cycles(0) {}
void appendStage(std::unique_ptr<Stage> S) { Stages.push_back(std::move(S)); }
void run();
};
} // namespace mca
-#endif
+#endif // LLVM_TOOLS_LLVM_MCA_PIPELINE_H
-//===--------------------- BackendPrinter.cpp -------------------*- C++ -*-===//
+//===--------------------- PipelinePrinter.cpp ------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
//===----------------------------------------------------------------------===//
/// \file
///
-/// This file implements the BackendPrinter interface.
+/// This file implements the PipelinePrinter interface.
///
//===----------------------------------------------------------------------===//
-#include "BackendPrinter.h"
+#include "PipelinePrinter.h"
#include "View.h"
#include "llvm/CodeGen/TargetSchedule.h"
using namespace llvm;
-void BackendPrinter::printReport(llvm::raw_ostream &OS) const {
+void PipelinePrinter::printReport(llvm::raw_ostream &OS) const {
for (const auto &V : Views)
V->printView(OS);
}
-//===--------------------- BackendPrinter.h ---------------------*- C++ -*-===//
+//===--------------------- PipelinePrinter.h --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
//===----------------------------------------------------------------------===//
/// \file
///
-/// This file implements class BackendPrinter.
+/// This file implements class PipelinePrinter.
///
-/// BackendPrinter allows the customization of the performance report.
+/// PipelinePrinter allows the customization of the performance report.
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_LLVM_MCA_BACKENDPRINTER_H
-#define LLVM_TOOLS_LLVM_MCA_BACKENDPRINTER_H
+#ifndef LLVM_TOOLS_LLVM_MCA_PIPELINEPRINTER_H
+#define LLVM_TOOLS_LLVM_MCA_PIPELINEPRINTER_H
-#include "Backend.h"
+#include "Pipeline.h"
#include "View.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/raw_ostream.h"
/// during the execution of the code. Internally, it delegates to other
/// classes the task of printing out timeline information as well as
/// resource pressure.
-class BackendPrinter {
- Backend &B;
+class PipelinePrinter {
+ Pipeline &P;
llvm::SmallVector<std::unique_ptr<View>, 8> Views;
public:
- BackendPrinter(Backend &backend) : B(backend) {}
+ PipelinePrinter(Pipeline &pipeline) : P(pipeline) {}
void addView(std::unique_ptr<View> V) {
- B.addEventListener(V.get());
+ P.addEventListener(V.get());
Views.emplace_back(std::move(V));
}
};
} // namespace mca
-#endif
+#endif // LLVM_TOOLS_LLVM_MCA_PIPELINEPRINTER_H
were inspired by the IACA tool from Intel.
The presence of long data dependency chains, as well as poor usage of hardware
-resources may lead to bottlenecks in the back-end. The tool is able to generate
+resources may lead to bottlenecks in the backend. The tool is able to generate
a detailed report which should help with identifying and analyzing sources of
bottlenecks.
The tool takes assembly code as input. Assembly code is parsed into a sequence
of MCInst with the help of the existing LLVM target assembly parsers. The parsed
-sequence of MCInst is then analyzed by a 'Backend' module to generate a
+sequence of MCInst is then analyzed by a 'Pipeline' module to generate a
performance report.
-The Backend module internally emulates the execution of the machine code
+The Pipeline module internally emulates the execution of the machine code
sequence in a loop of iterations (which by default is 100). At the end of this
-process, the backend collects a number of statistics which are then printed out
+process, the pipeline collects a number of statistics which are then printed out
in the form of a report.
Here is an example of performance report generated by the tool for a dot-product
JLSAGU, 0/12
///////////////////
-Based on the verbose report, the backend was only able to dispatch two
+Based on the verbose report, the pipeline was only able to dispatch two
instructions 51.5% of the time. The dispatch group was limited to one
instruction 44.6% of the cycles, which corresponds to 272 cycles.
LLVM-MCA instruction flow
-------------------------
-This section describes the instruction flow through the out-of-order backend, as
-well as the functional units involved in the process.
+This section describes the instruction flow through the out-of-order backend,
+as well as the functional units involved in the process.
An instruction goes through a default sequence of stages:
- Dispatch (Instruction is dispatched to the schedulers).
///
/// This file define class ResourcePressureView.
/// Class ResourcePressureView observes hardware events generated by
-/// the Backend object and collects statistics related to resource usage at
+/// the Pipeline object and collects statistics related to resource usage at
/// instruction granularity.
/// Resource pressure information is then printed out to a stream in the
/// form of a table like the one from the example below:
namespace mca {
-class Backend;
-
/// This class collects resource pressure statistics and it is able to print
/// out all the collected information as a table to an output stream.
class ResourcePressureView : public View {
//===----------------------------------------------------------------------===//
#include "RetireStage.h"
-#include "Backend.h"
#include "HWEventListener.h"
+#include "Pipeline.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
namespace mca {
-class Backend;
+class Pipeline;
class RetireStage : public Stage {
// Owner will go away when we move listeners/eventing to the stages.
- Backend *Owner;
+ Pipeline *Owner;
RetireControlUnit &RCU;
RegisterFile &PRF;
public:
- RetireStage(Backend *B, RetireControlUnit &R, RegisterFile &F)
- : Stage(), Owner(B), RCU(R), PRF(F) {}
+ RetireStage(Pipeline *P, RetireControlUnit &R, RegisterFile &F)
+ : Stage(), Owner(P), RCU(R), PRF(F) {}
RetireStage(const RetireStage &Other) = delete;
RetireStage &operator=(const RetireStage &Other) = delete;
//===----------------------------------------------------------------------===//
#include "Scheduler.h"
-#include "Backend.h"
#include "HWEventListener.h"
+#include "Pipeline.h"
#include "Support.h"
#include "llvm/Support/raw_ostream.h"
//===----------------------------------------------------------------------===//
/// \file
///
-/// This file implements a few helper functions used by various backend
+/// This file implements a few helper functions used by various pipeline
/// components.
///
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
/// \file
///
-/// Helper functions used by various backend components.
+/// Helper functions used by various pipeline components.
///
//===----------------------------------------------------------------------===//
///
/// This file implements a timeline view for the llvm-mca tool.
///
-/// Class TimelineView observes events generated by the backend. For every
-/// instruction executed by the backend, it stores information related to
+/// Class TimelineView observes events generated by the pipeline. For every
+/// instruction executed by the pipeline, it stores information related to
/// state transition. It then plots that information in the form of a table
/// as reported by the example below:
///
/// This class listens to instruction state transition events
/// in order to construct a timeline information.
///
-/// For every instruction executed by the Backend, this class constructs
+/// For every instruction executed by the Pipeline, this class constructs
/// a TimelineViewEntry object. TimelineViewEntry objects are then used
/// to print the timeline information, as well as the "average wait times"
/// for every instruction in the input assembly sequence.
//
//===----------------------------------------------------------------------===//
-#include "BackendPrinter.h"
#include "CodeRegion.h"
#include "DispatchStage.h"
#include "DispatchStatistics.h"
#include "FetchStage.h"
#include "InstructionInfoView.h"
#include "InstructionTables.h"
+#include "Pipeline.h"
+#include "PipelinePrinter.h"
#include "RegisterFile.h"
#include "RegisterFileStatistics.h"
#include "ResourcePressureView.h"
mca::Scheduler HWS(SM, LoadQueueSize, StoreQueueSize, AssumeNoAlias);
// Create the pipeline and add stages to it.
- auto B = llvm::make_unique<mca::Backend>(
+ auto P = llvm::make_unique<mca::Pipeline>(
Width, RegisterFileSize, LoadQueueSize, StoreQueueSize, AssumeNoAlias);
- B->appendStage(llvm::make_unique<mca::FetchStage>(IB, S));
- B->appendStage(llvm::make_unique<mca::DispatchStage>(
- B.get(), *STI, *MRI, RegisterFileSize, Width, RCU, PRF, HWS));
- B->appendStage(llvm::make_unique<mca::RetireStage>(B.get(), RCU, PRF));
- B->appendStage(llvm::make_unique<mca::ExecuteStage>(B.get(), RCU, HWS));
- mca::BackendPrinter Printer(*B);
+ P->appendStage(llvm::make_unique<mca::FetchStage>(IB, S));
+ P->appendStage(llvm::make_unique<mca::DispatchStage>(
+ P.get(), *STI, *MRI, RegisterFileSize, Width, RCU, PRF, HWS));
+ P->appendStage(llvm::make_unique<mca::RetireStage>(P.get(), RCU, PRF));
+ P->appendStage(llvm::make_unique<mca::ExecuteStage>(P.get(), RCU, HWS));
+ mca::PipelinePrinter Printer(*P);
if (PrintSummaryView)
Printer.addView(llvm::make_unique<mca::SummaryView>(SM, S, Width));
*STI, *IP, S, TimelineMaxIterations, TimelineMaxCycles));
}
- B->run();
+ P->run();
Printer.printReport(TOF->os());
}