Index: llvm/docs/CommandGuide/llvm-mca.rst =================================================================== --- llvm/docs/CommandGuide/llvm-mca.rst +++ llvm/docs/CommandGuide/llvm-mca.rst @@ -206,6 +206,12 @@ can be expensive, and it is disabled by default. Bottlenecks are highlighted in the summary view. +.. option:: -json + + Print the requested views in JSON format. The instructions and the processor + resources are printed as members of special top level JSON objects. The + individual views refer to them by index. + EXIT STATUS ----------- Index: llvm/test/tools/llvm-mca/JSON/X86/views.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-mca/JSON/X86/views.s @@ -0,0 +1,331 @@ +# NOTE: Assertions have been autogenerated by utils/update_mca_test_checks.py +# Verify that we create proper JSON for the MCA views TimelineView, ResourcePressureview, +# InstructionInfoView and SummaryView. + +# RUN: llvm-mca -mcpu=haswell --json --timeline-max-iterations=1 --timeline < %s | FileCheck %s + +add %eax, %eax +add %ebx, %ebx +add %ecx, %ecx +add %edx, %edx + +# CHECK: { +# CHECK-NEXT: "CPU": { +# 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: "HWPort01", +# CHECK-NEXT: "HWPort04", +# CHECK-NEXT: "HWPort05", +# CHECK-NEXT: "HWPort06", +# CHECK-NEXT: "HWPort15", +# CHECK-NEXT: "HWPort16", +# CHECK-NEXT: "HWPort23", +# CHECK-NEXT: "HWPort56", +# CHECK-NEXT: "HWPort015", +# CHECK-NEXT: "HWPort056", +# CHECK-NEXT: "HWPort237", +# CHECK-NEXT: "HWPort0156", +# CHECK-NEXT: "HWPortAny" +# CHECK-NEXT: ] +# CHECK-NEXT: }, +# CHECK-NEXT: "InstructionInfoView": [ +# 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: "InstructionSequence": [ +# 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: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 100 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 100 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 100 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 100 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 100 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 100 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 100 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 100 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "Denominator": 1, +# CHECK-NEXT: "Numerator": 0 +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: }, +# CHECK-NEXT: "SummaryView": { +# CHECK-NEXT: "BlockRThroughput": 1, +# CHECK-NEXT: "DispatchWidth": 4, +# CHECK-NEXT: "IPC": 3.883495145631068, +# CHECK-NEXT: "Instructions": 400, +# CHECK-NEXT: "Iterations": 100, +# CHECK-NEXT: "TotalCycles": 103, +# CHECK-NEXT: "TotaluOps": 400, +# CHECK-NEXT: "uOpsPerCycle": 3.883495145631068 +# CHECK-NEXT: }, +# CHECK-NEXT: "TimelineView": { +# CHECK-NEXT: "TimelineInfo": [ +# CHECK-NEXT: { +# CHECK-NEXT: "CycleDispatched": 0, +# CHECK-NEXT: "CycleExecuted": 2, +# CHECK-NEXT: "CycleIssued": 1, +# CHECK-NEXT: "CycleReady": 0, +# CHECK-NEXT: "CycleRetired": 3 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "CycleDispatched": 0, +# CHECK-NEXT: "CycleExecuted": 2, +# CHECK-NEXT: "CycleIssued": 1, +# CHECK-NEXT: "CycleReady": 0, +# CHECK-NEXT: "CycleRetired": 3 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "CycleDispatched": 0, +# CHECK-NEXT: "CycleExecuted": 2, +# CHECK-NEXT: "CycleIssued": 1, +# CHECK-NEXT: "CycleReady": 0, +# CHECK-NEXT: "CycleRetired": 3 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "CycleDispatched": 0, +# CHECK-NEXT: "CycleExecuted": 2, +# CHECK-NEXT: "CycleIssued": 1, +# CHECK-NEXT: "CycleReady": 0, +# CHECK-NEXT: "CycleRetired": 3 +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } Index: llvm/tools/llvm-mca/PipelinePrinter.h =================================================================== --- llvm/tools/llvm-mca/PipelinePrinter.h +++ llvm/tools/llvm-mca/PipelinePrinter.h @@ -46,6 +46,8 @@ } void printReport(llvm::raw_ostream &OS) const; + void printJSON(llvm::raw_ostream &OS, llvm::ArrayRef Insts, + StringRef MCPU, const llvm::MCSubtargetInfo &STI) const; }; } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/PipelinePrinter.cpp =================================================================== --- llvm/tools/llvm-mca/PipelinePrinter.cpp +++ llvm/tools/llvm-mca/PipelinePrinter.cpp @@ -13,6 +13,7 @@ #include "PipelinePrinter.h" #include "Views/View.h" +#include "llvm/Support/JSON.h" namespace llvm { namespace mca { @@ -21,5 +22,27 @@ for (const auto &V : Views) V->printView(OS); } + +void PipelinePrinter::printJSON(llvm::raw_ostream &OS, + llvm::ArrayRef Insts, + StringRef MCPU, + const llvm::MCSubtargetInfo &STI) const { + json::Object JO; + + assert(InstructionViewJSONHandler::GlobalInstViewJSONHandler && + "global instruction view JSON handler not present"); + // A top-level object for the instructions. + JO.try_emplace( + "InstructionSequence", + InstructionViewJSONHandler::GlobalInstViewJSONHandler->instToJSON()); + // A top level object to describe the CPU. + JO.try_emplace("CPU", View::CPUtoJSON(MCPU, STI)); + + // Incorporate the individual views. + for (const auto &V : Views) + JO.try_emplace(V->getNameAsString().str(), V->toJSON()); + + OS << formatv("{0:2}", json::Value(std::move(JO))) << "\n"; +} } // namespace mca. } // namespace llvm Index: llvm/tools/llvm-mca/Views/BottleneckAnalysis.h =================================================================== --- llvm/tools/llvm-mca/Views/BottleneckAnalysis.h +++ llvm/tools/llvm-mca/Views/BottleneckAnalysis.h @@ -332,6 +332,7 @@ void onEvent(const HWInstructionEvent &Event) override; void printView(raw_ostream &OS) const override; + StringRef getNameAsString() const override { return "BottleneckAnalysis"; } #ifndef NDEBUG void dump(raw_ostream &OS, MCInstPrinter &MCIP) const { DG.dump(OS, MCIP); } Index: llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp =================================================================== --- llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp +++ llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp @@ -287,7 +287,6 @@ const MCInst &MCI, bool UseDifferentColor) const { FOS.PadToColumn(14); - if (UseDifferentColor) FOS.changeColor(raw_ostream::CYAN, true, false); FOS << printInstructionString(MCI); Index: llvm/tools/llvm-mca/Views/DispatchStatistics.h =================================================================== --- llvm/tools/llvm-mca/Views/DispatchStatistics.h +++ llvm/tools/llvm-mca/Views/DispatchStatistics.h @@ -78,6 +78,7 @@ printDispatchStalls(OS); printDispatchHistogram(OS); } + StringRef getNameAsString() const override { return "DispatchStatistics"; } }; } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/Views/InstructionInfoView.h =================================================================== --- llvm/tools/llvm-mca/Views/InstructionInfoView.h +++ llvm/tools/llvm-mca/Views/InstructionInfoView.h @@ -65,6 +65,7 @@ }; using IIVDVec = SmallVector; + json::Object toJSON(const InstructionInfoViewData &IIVD) const; /// Place the data into the array of InstructionInfoViewData IIVD. void collectData(MutableArrayRef IIVD) const; @@ -77,6 +78,8 @@ PrintEncodings(ShouldPrintEncodings) {} void printView(llvm::raw_ostream &OS) const override; + StringRef getNameAsString() const override { return "InstructionInfoView"; } + json::Value toJSON() const; }; } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/Views/InstructionInfoView.cpp =================================================================== --- llvm/tools/llvm-mca/Views/InstructionInfoView.cpp +++ llvm/tools/llvm-mca/Views/InstructionInfoView.cpp @@ -13,6 +13,7 @@ #include "Views/InstructionInfoView.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/JSON.h" namespace llvm { namespace mca { @@ -118,5 +119,34 @@ IIVDEntry.hasUnmodeledSideEffects = MCDesc.hasUnmodeledSideEffects(); } } + +// Construct a JSON object from a single InstructionInfoViewData object. +json::Object InstructionInfoView::toJSON(const InstructionInfoViewData &IIVD) const { + json::Object JO({{"NumMicroOpcodes", IIVD.NumMicroOpcodes}, + {"Latency", IIVD.Latency}, + {"mayLoad", IIVD.mayLoad}, + {"mayStore", IIVD.mayStore}, + {"hasUnmodeledSideEffects", IIVD.hasUnmodeledSideEffects}}); + JO.try_emplace("RThroughput", IIVD.RThroughput.getValueOr(0.0)); + return JO; +} + +json::Value InstructionInfoView::toJSON() const { + ArrayRef Source = getSource(); + if (!Source.size()) + return json::Value(0); + + IIVDVec IIVD(Source.size()); + collectData(IIVD); + + json::Array InstInfo; + for (const auto I : enumerate(IIVD)) { + const InstructionInfoViewData &IIVDEntry = I.value(); + json::Object JO = toJSON(IIVDEntry); + JO.try_emplace("Instruction", (unsigned)I.index()); + InstInfo.push_back(std::move(JO)); + } + return json::Value(std::move(InstInfo)); +} } // namespace mca. } // namespace llvm Index: llvm/tools/llvm-mca/Views/RegisterFileStatistics.h =================================================================== --- llvm/tools/llvm-mca/Views/RegisterFileStatistics.h +++ llvm/tools/llvm-mca/Views/RegisterFileStatistics.h @@ -73,6 +73,9 @@ void onCycleEnd() override; void onEvent(const HWInstructionEvent &Event) override; void printView(llvm::raw_ostream &OS) const override; + StringRef getNameAsString() const override { + return "RegisterFileStatistics"; + } }; } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/Views/ResourcePressureView.h =================================================================== --- llvm/tools/llvm-mca/Views/ResourcePressureView.h +++ llvm/tools/llvm-mca/Views/ResourcePressureView.h @@ -63,6 +63,7 @@ #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/JSON.h" namespace llvm { namespace mca { @@ -93,6 +94,8 @@ printResourcePressurePerIter(OS); printResourcePressurePerInst(OS); } + StringRef getNameAsString() const override { return "ResourcePressureView"; } + json::Value toJSON() const override; }; } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/Views/ResourcePressureView.cpp =================================================================== --- llvm/tools/llvm-mca/Views/ResourcePressureView.cpp +++ llvm/tools/llvm-mca/Views/ResourcePressureView.cpp @@ -171,5 +171,19 @@ ++InstrIndex; } } + +json::Value ResourcePressureView::toJSON() const { + // We're dumping the instructions and the ResourceUsage array. + json::Array ResourcePressureInfo; + + for (const ResourceCycles &RU : ResourceUsage) { + ResourcePressureInfo.push_back( + json::Object({{"Numerator", RU.getNumerator()}, + {"Denominator", RU.getDenominator()}})); + } + + json::Object JO({{"ResourcePressureInfo", std::move(ResourcePressureInfo)}}); + return JO; +} } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h =================================================================== --- llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h +++ llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h @@ -52,6 +52,9 @@ void onEvent(const HWInstructionEvent &Event) override; void onCycleEnd() override; void printView(llvm::raw_ostream &OS) const override; + StringRef getNameAsString() const override { + return "RetireControlUnitStatistics"; + } }; } // namespace mca Index: llvm/tools/llvm-mca/Views/SchedulerStatistics.h =================================================================== --- llvm/tools/llvm-mca/Views/SchedulerStatistics.h +++ llvm/tools/llvm-mca/Views/SchedulerStatistics.h @@ -88,6 +88,7 @@ llvm::ArrayRef Buffers) override; void printView(llvm::raw_ostream &OS) const override; + StringRef getNameAsString() const override { return "SchedulerStatistics"; } }; } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/Views/SummaryView.h =================================================================== --- llvm/tools/llvm-mca/Views/SummaryView.h +++ llvm/tools/llvm-mca/Views/SummaryView.h @@ -87,6 +87,8 @@ void onCycleEnd() override { ++TotalCycles; } void onEvent(const HWInstructionEvent &Event) override; void printView(llvm::raw_ostream &OS) const override; + StringRef getNameAsString() const override { return "SummaryView"; } + json::Value toJSON() const override; }; } // namespace mca Index: llvm/tools/llvm-mca/Views/SummaryView.cpp =================================================================== --- llvm/tools/llvm-mca/Views/SummaryView.cpp +++ llvm/tools/llvm-mca/Views/SummaryView.cpp @@ -96,5 +96,19 @@ DV.BlockRThroughput = computeBlockRThroughput(SM, DispatchWidth, NumMicroOps, ProcResourceUsage); } + +json::Value SummaryView::toJSON() const { + DisplayValues DV; + collectData(DV); + json::Object JO({{"Iterations", DV.Iterations}, + {"Instructions", DV.TotalInstructions}, + {"TotalCycles", DV.TotalCycles}, + {"TotaluOps", DV.TotalUOps}, + {"DispatchWidth", DV.DispatchWidth}, + {"uOpsPerCycle", DV.UOpsPerCycle}, + {"IPC", DV.IPC}, + {"BlockRThroughput", DV.BlockRThroughput}}); + return JO; +} } // namespace mca. } // namespace llvm Index: llvm/tools/llvm-mca/Views/TimelineView.h =================================================================== --- llvm/tools/llvm-mca/Views/TimelineView.h +++ llvm/tools/llvm-mca/Views/TimelineView.h @@ -106,6 +106,7 @@ #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" namespace llvm { @@ -178,6 +179,8 @@ printTimeline(OS); printAverageWaitTimes(OS); } + StringRef getNameAsString() const override { return "TimelineView"; } + json::Value toJSON() const override; }; } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/Views/TimelineView.cpp =================================================================== --- llvm/tools/llvm-mca/Views/TimelineView.cpp +++ llvm/tools/llvm-mca/Views/TimelineView.cpp @@ -297,5 +297,19 @@ } } } + +json::Value TimelineView::toJSON() const { + json::Array TimelineInfo; + + for (const TimelineViewEntry &TLE : Timeline) { + TimelineInfo.push_back( + json::Object({{"CycleDispatched", TLE.CycleDispatched}, + {"CycleReady", TLE.CycleReady}, + {"CycleIssued", TLE.CycleIssued}, + {"CycleExecuted", TLE.CycleExecuted}, + {"CycleRetired", TLE.CycleRetired}})); + } + return json::Object({{"TimelineInfo", std::move(TimelineInfo)}}); +} } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/Views/View.h =================================================================== --- llvm/tools/llvm-mca/Views/View.h +++ llvm/tools/llvm-mca/Views/View.h @@ -18,6 +18,7 @@ #include "llvm/MC/MCInstPrinter.h" #include "llvm/MCA/HWEventListener.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/JSON.h" namespace llvm { namespace mca { @@ -26,7 +27,14 @@ public: virtual void printView(llvm::raw_ostream &OS) const = 0; virtual ~View() = default; + virtual StringRef getNameAsString() const = 0; + virtual json::Value toJSON() const { + return json::Value("Not implemented"); + } void anchor() override; + + static json::Value CPUtoJSON(StringRef MCPU, + const llvm::MCSubtargetInfo &STI); }; // The base class for views that deal with individual machine instructions. @@ -50,11 +58,34 @@ // The result should be used or copied before the next call to // printInstructionString() as it will overwrite the previous result. StringRef printInstructionString(const llvm::MCInst &MCI) const; - const llvm::MCSubtargetInfo &getSubTargetInfo() const { return STI; } + llvm::MCInstPrinter &getInstPrinter() const { return MCIP; } llvm::ArrayRef getSource() const { return Source; } }; + +// A special class to create the JSON value that describes the instructions. +// There is only one such value and all the views refer to the individual +// instructions by index. +class InstructionViewJSONHandler : public InstructionView { + // Dummy definitions for pure virtual functions. + void printView(llvm::raw_ostream &) const {} + StringRef getNameAsString() const { return ""; } + +public: + InstructionViewJSONHandler(const llvm::MCSubtargetInfo &STI, + llvm::MCInstPrinter &Printer, + llvm::ArrayRef S) + : InstructionView(STI, Printer, S) {} + + ~InstructionViewJSONHandler() = default; + + // Return a JSON value that contains an array of instruction strings + // derived from Source. + json::Value instToJSON(); + // Pointer to a single global InstructionView object. + static std::unique_ptr GlobalInstViewJSONHandler; +}; } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/Views/View.cpp =================================================================== --- llvm/tools/llvm-mca/Views/View.cpp +++ llvm/tools/llvm-mca/Views/View.cpp @@ -12,6 +12,8 @@ //===----------------------------------------------------------------------===// #include "Views/View.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSubtargetInfo.h" namespace llvm { namespace mca { @@ -25,5 +27,29 @@ // Remove any tabs or spaces at the beginning of the instruction. return StringRef(InstructionString).ltrim(); } + + json::Value InstructionViewJSONHandler::instToJSON() { + json::Array SourceInfo; + for (const auto &MCI : getSource()) { + StringRef Instruction = printInstructionString(MCI); + SourceInfo.push_back(Instruction.str()); + } + return SourceInfo; + } + + json::Value View::CPUtoJSON(StringRef MCPU, + const llvm::MCSubtargetInfo &STI) { + json::Array Resources; + const MCSchedModel &SM = STI.getSchedModel(); + for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) { + const MCProcResourceDesc &ProcResource = *SM.getProcResource(I); + Resources.push_back(ProcResource.Name); + } + return json::Object( + {{"CPUName", MCPU}, {"Resources", std::move(Resources)}}); + } + + std::unique_ptr + InstructionViewJSONHandler::GlobalInstViewJSONHandler; } // namespace mca } // namespace llvm Index: llvm/tools/llvm-mca/llvm-mca.cpp =================================================================== --- llvm/tools/llvm-mca/llvm-mca.cpp +++ llvm/tools/llvm-mca/llvm-mca.cpp @@ -96,6 +96,11 @@ cl::desc("Additional target features."), cl::cat(ToolOptions)); +static cl::opt + PrintJson("json", + cl::desc("Print the output in json format"), + cl::cat(ToolOptions), cl::init(false)); + static cl::opt OutputAsmVariant("output-asm-variant", cl::desc("Syntax variant to use for output printing"), @@ -559,10 +564,19 @@ TimelineMaxCycles)); } + // Create a singleton InstructionInfoView object that is responsible for + // producing a single JSON value that holds the instruction strings. + if (PrintJson) + mca::InstructionViewJSONHandler::GlobalInstViewJSONHandler = + std::make_unique(*STI, *IP, Insts); + if (!runPipeline(*P)) return 1; - Printer.printReport(TOF->os()); + if (PrintJson) + Printer.printJSON(TOF->os(), Insts, MCPU, *STI); + else + Printer.printReport(TOF->os()); // Clear the InstrBuilder internal state in preparation for another round. IB.clear();