[llvm-mca] Add flag -instruction-tables to print the theoretical resource pressure distribution for instructions (PR36874)
The goal of this patch is to address most of PR36874. To fully fix PR36874 we
need to split the "InstructionInfo" view from the "SummaryView". That would make
easy to check the latency and rthroughput as well.
The patch reuses all the logic from ResourcePressureView to print out the
"instruction tables".
We have an entry for every instruction in the input sequence. Each entry reports
the theoretical resource pressure distribution. Resource pressure is uniformly
distributed across all the processor resource units of a group.
At the moment, the backend pipeline is not configurable, so the only way to fix
this is by creating a different driver that simply sends instruction events to
the resource pressure view. That means, we don't use the Backend interface.
Instead, it is simpler to just have a different code-path for when flag
-instruction-tables is specified.
Once Clement addresses bug 36663, then we can port the "instruction tables"
logic into a stage of our configurable pipeline.
Updated the BtVer2 test cases (thanks Simon for the help). Now we pass flag
-instruction-tables to each modified test.
Differential Revision: https://reviews.llvm.org/D44839
llvm-svn: 328487
diff --git a/llvm/tools/llvm-mca/CMakeLists.txt b/llvm/tools/llvm-mca/CMakeLists.txt
index 9358c08..36af64c 100644
--- a/llvm/tools/llvm-mca/CMakeLists.txt
+++ b/llvm/tools/llvm-mca/CMakeLists.txt
@@ -18,6 +18,7 @@
InstrBuilder.cpp
Instruction.cpp
InstructionInfoView.cpp
+ InstructionTables.cpp
LSUnit.cpp
llvm-mca.cpp
ResourcePressureView.cpp
diff --git a/llvm/tools/llvm-mca/InstrBuilder.h b/llvm/tools/llvm-mca/InstrBuilder.h
index a74e0af..a3b7001 100644
--- a/llvm/tools/llvm-mca/InstrBuilder.h
+++ b/llvm/tools/llvm-mca/InstrBuilder.h
@@ -51,6 +51,13 @@
}
const InstrDesc &getOrCreateInstrDesc(const llvm::MCInst &MCI);
+ // Returns an array of processor resource masks.
+ // Masks are computed by function mca::computeProcResourceMasks. see
+ // Support.h for a description of how masks are computed and how masks can be
+ // used to solve set membership problems.
+ llvm::ArrayRef<uint64_t> getProcResourceMasks() const {
+ return ProcResourceMasks;
+ }
std::unique_ptr<Instruction> createInstruction(unsigned Idx,
const llvm::MCInst &MCI);
diff --git a/llvm/tools/llvm-mca/InstructionTables.cpp b/llvm/tools/llvm-mca/InstructionTables.cpp
new file mode 100644
index 0000000..044b516
--- /dev/null
+++ b/llvm/tools/llvm-mca/InstructionTables.cpp
@@ -0,0 +1,80 @@
+//===--------------------- InstructionTables.cpp ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// 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.
+///
+//===----------------------------------------------------------------------===//
+
+#include "InstructionTables.h"
+
+namespace mca {
+
+using namespace llvm;
+
+using ResourceRef = std::pair<uint64_t, uint64_t>;
+
+void InstructionTables::run() {
+ ArrayRef<uint64_t> Masks = IB.getProcResourceMasks();
+ SmallVector<std::pair<ResourceRef, double>, 4> UsedResources;
+
+ // Create an instruction descriptor for every instruction in the sequence.
+ while (S.hasNext()) {
+ UsedResources.clear();
+ InstRef IR = S.peekNext();
+ std::unique_ptr<Instruction> Inst = IB.createInstruction(IR.first, *IR.second);
+ const InstrDesc &Desc = Inst->getDesc();
+ // Now identify the resources consumed by this instruction.
+ for (const std::pair<uint64_t, ResourceUsage> Resource : Desc.Resources) {
+ // Skip zero-cycle resources (i.e. unused resources).
+ if (!Resource.second.size())
+ continue;
+ double Cycles = static_cast<double>(Resource.second.size());
+ unsigned Index =
+ std::distance(Masks.begin(), std::find(Masks.begin(), Masks.end(),
+ Resource.first));
+ const MCProcResourceDesc &ProcResource = *SM.getProcResource(Index);
+ unsigned NumUnits = ProcResource.NumUnits;
+ if (!ProcResource.SubUnitsIdxBegin) {
+ // The number of cycles consumed by each unit.
+ Cycles /= NumUnits;
+ for (unsigned I = 0, E = NumUnits; I < E; ++I) {
+ ResourceRef ResourceUnit = std::make_pair(Index, 1U << I);
+ UsedResources.emplace_back(std::make_pair(ResourceUnit, Cycles));
+ }
+ continue;
+ }
+
+ // This is a group. Obtain the set of resources contained in this
+ // group. Some of these resources may implement multiple units.
+ // Uniformly distribute Cycles across all of the units.
+ for (unsigned I1 = 0; I1 < NumUnits; ++I1) {
+ unsigned SubUnitIdx = ProcResource.SubUnitsIdxBegin[I1];
+ const MCProcResourceDesc &SubUnit = *SM.getProcResource(SubUnitIdx);
+ // Compute the number of cycles consumed by each resource unit.
+ double RUCycles = Cycles / (NumUnits * SubUnit.NumUnits);
+ for (unsigned I2 = 0, E2 = SubUnit.NumUnits; I2 < E2; ++I2) {
+ ResourceRef ResourceUnit = std::make_pair(SubUnitIdx, 1U << I2);
+ UsedResources.emplace_back(std::make_pair(ResourceUnit, RUCycles));
+ }
+ }
+ }
+
+ // Now send a fake instruction issued event to all the listeners.
+ HWInstructionIssuedEvent Event(IR.first, UsedResources);
+ for (HWEventListener *Listener : Listeners)
+ Listener->onInstructionEvent(Event);
+ S.updateNext();
+ }
+}
+
+} // namespace mca
diff --git a/llvm/tools/llvm-mca/InstructionTables.h b/llvm/tools/llvm-mca/InstructionTables.h
new file mode 100644
index 0000000..97dd9b8
--- /dev/null
+++ b/llvm/tools/llvm-mca/InstructionTables.h
@@ -0,0 +1,47 @@
+//===--------------------- InstructionTables.h ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file implements a custom driver to generate instruction tables.
+/// See the description of command-line flag -instruction-tables in
+/// docs/CommandGuide/lvm-mca.rst
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_MCA_INSTRUCTIONTABLES_H
+#define LLVM_TOOLS_LLVM_MCA_INSTRUCTIONTABLES_H
+
+#include "HWEventListener.h"
+#include "InstrBuilder.h"
+#include "SourceMgr.h"
+#include "llvm/MC/MCSchedule.h"
+
+namespace mca {
+
+class InstructionTables {
+ const llvm::MCSchedModel &SM;
+ InstrBuilder &IB;
+ SourceMgr &S;
+ std::set<HWEventListener *> Listeners;
+
+public:
+ InstructionTables(const llvm::MCSchedModel &Model, InstrBuilder &Builder,
+ SourceMgr &Source)
+ : SM(Model), IB(Builder), S(Source) {}
+
+ void addEventListener(HWEventListener *Listener) {
+ if (Listener)
+ Listeners.insert(Listener);
+ }
+
+ void run();
+};
+} // namespace mca
+
+#endif
diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index b397a4c..127b22f 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -24,6 +24,7 @@
#include "BackendPrinter.h"
#include "BackendStatistics.h"
#include "InstructionInfoView.h"
+#include "InstructionTables.h"
#include "ResourcePressureView.h"
#include "SummaryView.h"
#include "TimelineView.h"
@@ -121,9 +122,15 @@
static cl::opt<unsigned>
LoadQueueSize("lqueue", cl::desc("Size of the load queue"), cl::init(0));
+
static cl::opt<unsigned>
StoreQueueSize("squeue", cl::desc("Size of the store queue"), cl::init(0));
+static cl::opt<bool>
+ PrintInstructionTables("instruction-tables",
+ cl::desc("Print instruction tables"),
+ cl::init(false));
+
static const Target *getTarget(const char *ProgName) {
TripleName = Triple::normalize(TripleName);
if (TripleName.empty())
@@ -260,8 +267,9 @@
MOFI.InitMCObjectFileInfo(TheTriple, /* PIC= */ false, Ctx);
std::unique_ptr<buffer_ostream> BOS;
+
std::unique_ptr<mca::SourceMgr> S =
- llvm::make_unique<mca::SourceMgr>(Iterations);
+ llvm::make_unique<mca::SourceMgr>(PrintInstructionTables ? 1 : Iterations);
MCStreamerWrapper Str(Ctx, S->getSequence());
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
@@ -326,6 +334,18 @@
std::unique_ptr<mca::InstrBuilder> IB =
llvm::make_unique<mca::InstrBuilder>(*STI, *MCII);
+ if (PrintInstructionTables) {
+ mca::InstructionTables IT(STI->getSchedModel(), *IB, *S);
+ mca::ResourcePressureView RPV(*STI, *IP, *S);
+ mca::InstructionInfoView IIV(*STI, *MCII, *S, *IP);
+ IT.addEventListener(&IIV);
+ IT.addEventListener(&RPV);
+ IT.run();
+ RPV.printView(TOF->os());
+ TOF->keep();
+ return 0;
+ }
+
std::unique_ptr<mca::Backend> B = llvm::make_unique<mca::Backend>(
*STI, *MRI, *IB, *S, Width, RegisterFileSize, MaxRetirePerCycle,
LoadQueueSize, StoreQueueSize, AssumeNoAlias);