1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 18:42:46 +02:00

[llvm-mca] Refactor the logic that prints JSON files.

Moved most of the printing logic into the PipelinePrinter.

This patch also fixes the JSON output when flag -instruction-tables is
specified.
This commit is contained in:
Andrea Di Biagio 2021-07-09 22:35:12 +01:00
parent 225e80a882
commit 01e80dc3be
8 changed files with 365 additions and 60 deletions

View File

@ -0,0 +1,277 @@
# NOTE: Assertions have been autogenerated by utils/update_mca_test_checks.py
# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=haswell --json -instruction-tables < %s | FileCheck %s
# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=haswell --json -instruction-tables -o %t.json < %s
# RUN: cat %t.json \
# RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \
# RUN: | FileCheck %s
# LLVM-MCA-BEGIN foo
add %eax, %eax
# LLVM-MCA-BEGIN bar
add %ebx, %ebx
add %ecx, %ecx
# LLVM-MCA-END bar
add %edx, %edx
# LLVM-MCA-END foo
# CHECK: {
# CHECK-NEXT: "Resources": {
# CHECK-NEXT: "CPUName": "haswell",
# CHECK-NEXT: "Resources": [
# CHECK-NEXT: "HWDivider",
# CHECK-NEXT: "HWFPDivider",
# CHECK-NEXT: "HWPort0",
# CHECK-NEXT: "HWPort1",
# CHECK-NEXT: "HWPort2",
# CHECK-NEXT: "HWPort3",
# CHECK-NEXT: "HWPort4",
# CHECK-NEXT: "HWPort5",
# CHECK-NEXT: "HWPort6",
# CHECK-NEXT: "HWPort7"
# CHECK-NEXT: ]
# CHECK-NEXT: },
# CHECK-NEXT: "bar": {
# CHECK-NEXT: "InstructionInfoView": {
# CHECK-NEXT: "InstructionList": [
# CHECK-NEXT: {
# CHECK-NEXT: "Instruction": 0,
# CHECK-NEXT: "Latency": 1,
# CHECK-NEXT: "NumMicroOpcodes": 1,
# CHECK-NEXT: "RThroughput": 0.25,
# CHECK-NEXT: "hasUnmodeledSideEffects": false,
# CHECK-NEXT: "mayLoad": false,
# CHECK-NEXT: "mayStore": false
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "Instruction": 1,
# CHECK-NEXT: "Latency": 1,
# CHECK-NEXT: "NumMicroOpcodes": 1,
# CHECK-NEXT: "RThroughput": 0.25,
# CHECK-NEXT: "hasUnmodeledSideEffects": false,
# CHECK-NEXT: "mayLoad": false,
# CHECK-NEXT: "mayStore": false
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: },
# CHECK-NEXT: "Instructions": [
# CHECK-NEXT: "addl\t%ebx, %ebx",
# CHECK-NEXT: "addl\t%ecx, %ecx"
# CHECK-NEXT: ],
# CHECK-NEXT: "ResourcePressureView": {
# CHECK-NEXT: "ResourcePressureInfo": [
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 0,
# CHECK-NEXT: "ResourceIndex": 2,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 0,
# CHECK-NEXT: "ResourceIndex": 3,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 0,
# CHECK-NEXT: "ResourceIndex": 7,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 0,
# CHECK-NEXT: "ResourceIndex": 8,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 1,
# CHECK-NEXT: "ResourceIndex": 2,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 1,
# CHECK-NEXT: "ResourceIndex": 3,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 1,
# CHECK-NEXT: "ResourceIndex": 7,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 1,
# CHECK-NEXT: "ResourceIndex": 8,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 2,
# CHECK-NEXT: "ResourceIndex": 2,
# CHECK-NEXT: "ResourceUsage": 0.5
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 2,
# CHECK-NEXT: "ResourceIndex": 3,
# CHECK-NEXT: "ResourceUsage": 0.5
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 2,
# CHECK-NEXT: "ResourceIndex": 7,
# CHECK-NEXT: "ResourceUsage": 0.5
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 2,
# CHECK-NEXT: "ResourceIndex": 8,
# CHECK-NEXT: "ResourceUsage": 0.5
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: "foo": {
# CHECK-NEXT: "InstructionInfoView": {
# CHECK-NEXT: "InstructionList": [
# CHECK-NEXT: {
# CHECK-NEXT: "Instruction": 0,
# CHECK-NEXT: "Latency": 1,
# CHECK-NEXT: "NumMicroOpcodes": 1,
# CHECK-NEXT: "RThroughput": 0.25,
# CHECK-NEXT: "hasUnmodeledSideEffects": false,
# CHECK-NEXT: "mayLoad": false,
# CHECK-NEXT: "mayStore": false
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "Instruction": 1,
# CHECK-NEXT: "Latency": 1,
# CHECK-NEXT: "NumMicroOpcodes": 1,
# CHECK-NEXT: "RThroughput": 0.25,
# CHECK-NEXT: "hasUnmodeledSideEffects": false,
# CHECK-NEXT: "mayLoad": false,
# CHECK-NEXT: "mayStore": false
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "Instruction": 2,
# CHECK-NEXT: "Latency": 1,
# CHECK-NEXT: "NumMicroOpcodes": 1,
# CHECK-NEXT: "RThroughput": 0.25,
# CHECK-NEXT: "hasUnmodeledSideEffects": false,
# CHECK-NEXT: "mayLoad": false,
# CHECK-NEXT: "mayStore": false
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "Instruction": 3,
# CHECK-NEXT: "Latency": 1,
# CHECK-NEXT: "NumMicroOpcodes": 1,
# CHECK-NEXT: "RThroughput": 0.25,
# CHECK-NEXT: "hasUnmodeledSideEffects": false,
# CHECK-NEXT: "mayLoad": false,
# CHECK-NEXT: "mayStore": false
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: },
# CHECK-NEXT: "Instructions": [
# CHECK-NEXT: "addl\t%eax, %eax",
# CHECK-NEXT: "addl\t%ebx, %ebx",
# CHECK-NEXT: "addl\t%ecx, %ecx",
# CHECK-NEXT: "addl\t%edx, %edx"
# CHECK-NEXT: ],
# CHECK-NEXT: "ResourcePressureView": {
# CHECK-NEXT: "ResourcePressureInfo": [
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 0,
# CHECK-NEXT: "ResourceIndex": 2,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 0,
# CHECK-NEXT: "ResourceIndex": 3,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 0,
# CHECK-NEXT: "ResourceIndex": 7,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 0,
# CHECK-NEXT: "ResourceIndex": 8,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 1,
# CHECK-NEXT: "ResourceIndex": 2,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 1,
# CHECK-NEXT: "ResourceIndex": 3,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 1,
# CHECK-NEXT: "ResourceIndex": 7,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 1,
# CHECK-NEXT: "ResourceIndex": 8,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 2,
# CHECK-NEXT: "ResourceIndex": 2,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 2,
# CHECK-NEXT: "ResourceIndex": 3,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 2,
# CHECK-NEXT: "ResourceIndex": 7,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 2,
# CHECK-NEXT: "ResourceIndex": 8,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 3,
# CHECK-NEXT: "ResourceIndex": 2,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 3,
# CHECK-NEXT: "ResourceIndex": 3,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 3,
# CHECK-NEXT: "ResourceIndex": 7,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 3,
# CHECK-NEXT: "ResourceIndex": 8,
# CHECK-NEXT: "ResourceUsage": 0.25
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 4,
# CHECK-NEXT: "ResourceIndex": 2,
# CHECK-NEXT: "ResourceUsage": 1
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 4,
# CHECK-NEXT: "ResourceIndex": 3,
# CHECK-NEXT: "ResourceUsage": 1
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 4,
# CHECK-NEXT: "ResourceIndex": 7,
# CHECK-NEXT: "ResourceUsage": 1
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "InstructionIndex": 4,
# CHECK-NEXT: "ResourceIndex": 8,
# CHECK-NEXT: "ResourceUsage": 1
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT: }

View File

@ -12,26 +12,56 @@
//===----------------------------------------------------------------------===//
#include "PipelinePrinter.h"
#include "CodeRegion.h"
#include "Views/InstructionView.h"
#include "Views/View.h"
namespace llvm {
namespace mca {
void PipelinePrinter::printRegionHeader(llvm::raw_ostream &OS) const {
StringRef RegionName;
if (!Region.getDescription().empty())
RegionName = Region.getDescription();
OS << "\n[" << RegionIdx << "] Code Region";
if (!RegionName.empty())
OS << " - " << RegionName;
OS << "\n\n";
}
json::Object PipelinePrinter::getJSONReportRegion() const {
json::Object JO;
for (const auto &V : Views) {
if (V->isSerializable()) {
for (const auto &V : Views)
if (V->isSerializable())
JO.try_emplace(V->getNameAsString().str(), V->toJSON());
}
}
return JO;
}
void PipelinePrinter::printReport(llvm::raw_ostream &OS) const {
json::Object JO;
for (const auto &V : Views) {
V->printView(OS);
}
void PipelinePrinter::printReport(json::Object &JO) const {
if (!RegionIdx)
JO.try_emplace("Resources", InstructionView::getJSONTargetInfo(STI));
StringRef RegionName;
if (Region.getDescription().empty())
RegionName = "main";
else
RegionName = Region.getDescription();
JO.try_emplace(RegionName, getJSONReportRegion());
}
} // namespace mca.
void PipelinePrinter::printReport(llvm::raw_ostream &OS) const {
// Don't print the header of this region if it is the default region, and if
// it doesn't have an end location.
if (Region.startLoc().isValid() || Region.endLoc().isValid())
printRegionHeader(OS);
for (const auto &V : Views)
V->printView(OS);
}
} // namespace mca
} // namespace llvm

View File

@ -18,6 +18,7 @@
#include "Views/View.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MCA/Pipeline.h"
#include "llvm/Support/raw_ostream.h"
@ -26,6 +27,8 @@
namespace llvm {
namespace mca {
class CodeRegion;
/// A printer class that knows how to collects statistics on the
/// code analyzed by the llvm-mca tool.
///
@ -35,10 +38,18 @@ namespace mca {
/// resource pressure.
class PipelinePrinter {
Pipeline &P;
const CodeRegion &Region;
unsigned RegionIdx;
const MCSubtargetInfo &STI;
llvm::SmallVector<std::unique_ptr<View>, 8> Views;
void printRegionHeader(llvm::raw_ostream &OS) const;
json::Object getJSONReportRegion() const;
public:
PipelinePrinter(Pipeline &pipeline) : P(pipeline) {}
PipelinePrinter(Pipeline &Pipe, const CodeRegion &R, unsigned Idx,
const MCSubtargetInfo &STI)
: P(Pipe), Region(R), RegionIdx(Idx), STI(STI), Views() {}
void addView(std::unique_ptr<View> V) {
P.addEventListener(V.get());
@ -46,7 +57,7 @@ public:
}
void printReport(llvm::raw_ostream &OS) const;
json::Object getJSONReportRegion() const;
void printReport(json::Object &JO) const;
};
} // namespace mca
} // namespace llvm

View File

@ -19,6 +19,8 @@
namespace llvm {
namespace mca {
InstructionView::~InstructionView() = default;
StringRef InstructionView::printInstructionString(const llvm::MCInst &MCI) const {
InstructionString = "";
MCIP.printInst(&MCI, 0, "", STI, InstrStream);
@ -36,9 +38,11 @@ json::Value InstructionView::toJSON() const {
return SourceInfo;
}
json::Object InstructionView::getJSONResources() const {
json::Object InstructionView::getJSONTargetInfo(const MCSubtargetInfo &STI) {
json::Array Resources;
const MCSchedModel &SM = STI.getSchedModel();
StringRef MCPU = STI.getCPU();
for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {
const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
unsigned NumUnits = ProcResource.NumUnits;

View File

@ -28,7 +28,6 @@ class InstructionView : public View {
const llvm::MCSubtargetInfo &STI;
llvm::MCInstPrinter &MCIP;
llvm::ArrayRef<llvm::MCInst> Source;
StringRef MCPU;
mutable std::string InstructionString;
mutable raw_string_ostream InstrStream;
@ -37,12 +36,10 @@ public:
void printView(llvm::raw_ostream &) const override {}
InstructionView(const llvm::MCSubtargetInfo &STI,
llvm::MCInstPrinter &Printer,
llvm::ArrayRef<llvm::MCInst> S,
StringRef MCPU = StringRef())
: STI(STI), MCIP(Printer), Source(S), MCPU(MCPU),
InstrStream(InstructionString) {}
llvm::ArrayRef<llvm::MCInst> S)
: STI(STI), MCIP(Printer), Source(S), InstrStream(InstructionString) {}
virtual ~InstructionView() = default;
virtual ~InstructionView();
StringRef getNameAsString() const override {
return "Instructions";
@ -56,11 +53,12 @@ public:
llvm::MCInstPrinter &getInstPrinter() const { return MCIP; }
llvm::ArrayRef<llvm::MCInst> getSource() const { return Source; }
json::Value toJSON() const override;
json::Object getJSONResources() const;
virtual void printViewJSON(llvm::raw_ostream &OS) override {
json::Value JV = toJSON();
OS << formatv("{0:2}", JV) << "\n";
}
static json::Object getJSONTargetInfo(const llvm::MCSubtargetInfo &STI);
};
} // namespace mca
} // namespace llvm

View File

@ -20,5 +20,12 @@ namespace mca {
void View::anchor() {}
void View::printViewJSON(llvm::raw_ostream &OS) {
json::Object JO;
JO.try_emplace(getNameAsString().str(), toJSON());
OS << formatv("{0:2}", json::Value(std::move(JO))) << "\n";
}
} // namespace mca
} // namespace llvm

View File

@ -25,23 +25,12 @@ namespace mca {
class View : public HWEventListener {
public:
enum OutputKind { OK_READABLE, OK_JSON };
void printView(OutputKind OutputKind, llvm::raw_ostream &OS) {
if (OutputKind == OK_JSON)
printViewJSON(OS);
else
printView(OS);
}
virtual ~View() = default;
virtual void printView(llvm::raw_ostream &OS) const = 0;
virtual void printViewJSON(llvm::raw_ostream &OS) {
json::Object JO;
JO.try_emplace(getNameAsString().str(), toJSON());
OS << formatv("{0:2}", json::Value(std::move(JO))) << "\n";
}
virtual ~View() = default;
virtual StringRef getNameAsString() const = 0;
virtual void printViewJSON(llvm::raw_ostream &OS);
virtual json::Value toJSON() const { return "not implemented"; }
virtual bool isSerializable() const { return true; }
void anchor() override;

View File

@ -529,16 +529,7 @@ int main(int argc, char **argv) {
if (Region->empty())
continue;
// Don't print the header of this region if it is the default region, and
// it doesn't have an end location.
if (!PrintJson &&
(Region->startLoc().isValid() || Region->endLoc().isValid())) {
TOF->os() << "\n[" << RegionIdx++ << "] Code Region";
StringRef Desc = Region->getDescription();
if (!Desc.empty())
TOF->os() << " - " << Desc;
TOF->os() << "\n\n";
}
IB.clear();
// Lower the MCInst sequence into an mca::Instruction sequence.
ArrayRef<MCInst> Insts = Region->getInstructions();
@ -579,7 +570,12 @@ int main(int argc, char **argv) {
auto P = std::make_unique<mca::Pipeline>();
P->appendStage(std::make_unique<mca::EntryStage>(S));
P->appendStage(std::make_unique<mca::InstructionTables>(SM));
mca::PipelinePrinter Printer(*P);
mca::PipelinePrinter Printer(*P, *Region, RegionIdx, *STI);
if (PrintJson) {
auto IV = std::make_unique<mca::InstructionView>(*STI, *IP, Insts);
Printer.addView(std::move(IV));
}
// Create the views for this pipeline, execute, and emit a report.
if (PrintInstructionInfoView) {
@ -593,13 +589,12 @@ int main(int argc, char **argv) {
return 1;
if (PrintJson) {
JSONOutput.try_emplace(!Region->getDescription().empty()
? Region->getDescription().str()
: "main",
Printer.getJSONReportRegion());
Printer.printReport(JSONOutput);
} else {
Printer.printReport(TOF->os());
}
++RegionIdx;
continue;
}
@ -614,15 +609,13 @@ int main(int argc, char **argv) {
// Create a basic pipeline simulating an out-of-order backend.
auto P = MCA.createDefaultPipeline(PO, S, *CB);
mca::PipelinePrinter Printer(*P);
mca::PipelinePrinter Printer(*P, *Region, RegionIdx, *STI);
// When we output JSON, we add a view that contains the instructions
// and CPU resource information.
if (PrintJson) {
auto IV = std::make_unique<mca::InstructionView>(*STI, *IP, Insts, MCPU);
if (JSONOutput.find("Resources") == JSONOutput.end()) {
JSONOutput.try_emplace("Resources", IV->getJSONResources());
}
auto IV = std::make_unique<mca::InstructionView>(*STI, *IP, Insts);
Printer.addView(std::move(IV));
}
@ -672,16 +665,12 @@ int main(int argc, char **argv) {
return 1;
if (PrintJson) {
JSONOutput.try_emplace(!Region->getDescription().empty()
? Region->getDescription().str()
: "main",
Printer.getJSONReportRegion());
Printer.printReport(JSONOutput);
} else {
Printer.printReport(TOF->os());
}
// Clear the InstrBuilder internal state in preparation for another round.
IB.clear();
++RegionIdx;
}
if (PrintJson)