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,166 @@ +# 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: "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: "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: } +# 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: } +# 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: } +# 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: } +# CHECK-NEXT: { +# CHECK-NEXT: "ResourcePressureView": { +# CHECK-NEXT: "ResourcePressureInfo": [ +# CHECK-NEXT: { +# CHECK-NEXT: "InstructionIndex": 0, +# CHECK-NEXT: "ResourceIndex": 8, +# CHECK-NEXT: "ResourceUsage": 1 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "InstructionIndex": 1, +# CHECK-NEXT: "ResourceIndex": 7, +# CHECK-NEXT: "ResourceUsage": 1 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "InstructionIndex": 2, +# CHECK-NEXT: "ResourceIndex": 3, +# CHECK-NEXT: "ResourceUsage": 1 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "InstructionIndex": 3, +# CHECK-NEXT: "ResourceIndex": 2, +# CHECK-NEXT: "ResourceUsage": 1 +# 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: } Index: llvm/tools/llvm-mca/CMakeLists.txt =================================================================== --- llvm/tools/llvm-mca/CMakeLists.txt +++ llvm/tools/llvm-mca/CMakeLists.txt @@ -19,6 +19,7 @@ Views/BottleneckAnalysis.cpp Views/DispatchStatistics.cpp Views/InstructionInfoView.cpp + Views/InstructionView.cpp Views/RegisterFileStatistics.cpp Views/ResourcePressureView.cpp Views/RetireControlUnitStatistics.cpp 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 { Index: llvm/tools/llvm-mca/Views/BottleneckAnalysis.h =================================================================== --- llvm/tools/llvm-mca/Views/BottleneckAnalysis.h +++ llvm/tools/llvm-mca/Views/BottleneckAnalysis.h @@ -80,14 +80,14 @@ #ifndef LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H #define LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H -#include "Views/View.h" +#include "Views/InstructionView.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCSchedule.h" #include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/raw_ostream.h" namespace llvm { namespace mca { @@ -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 @@ -34,7 +34,7 @@ #ifndef LLVM_TOOLS_LLVM_MCA_INSTRUCTIONINFOVIEW_H #define LLVM_TOOLS_LLVM_MCA_INSTRUCTIONINFOVIEW_H -#include "Views/View.h" +#include "Views/InstructionView.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCInst.h" @@ -55,6 +55,7 @@ CodeEmitter &CE; bool PrintEncodings; +protected: struct InstructionInfoViewData { unsigned NumMicroOpcodes = 0; unsigned Latency = 0; @@ -77,6 +78,22 @@ PrintEncodings(ShouldPrintEncodings) {} void printView(llvm::raw_ostream &OS) const override; + StringRef getNameAsString() const override { return "InstructionInfoView"; } +}; + +class InstructionInfoViewJSON : public InstructionInfoView { + json::Value toJSON() const; + json::Object toJSON(const InstructionInfoViewData &IIVD) const; + +public: + InstructionInfoViewJSON(const llvm::MCSubtargetInfo &ST, + const llvm::MCInstrInfo &II, CodeEmitter &C, + bool ShouldPrintEncodings, + llvm::ArrayRef S, + llvm::MCInstPrinter &IP) + : InstructionInfoView(ST, II, C, ShouldPrintEncodings, S, IP) {} + + void printView(llvm::raw_ostream &OS) const override; }; } // 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,41 @@ IIVDEntry.hasUnmodeledSideEffects = MCDesc.hasUnmodeledSideEffects(); } } + +// Construct a JSON object from a single InstructionInfoViewData object. +json::Object +InstructionInfoViewJSON::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 InstructionInfoViewJSON::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)); +} + +void InstructionInfoViewJSON::printView(llvm::raw_ostream &OS) const { + json::Object JO; + JO.try_emplace(getNameAsString().str(), toJSON()); + OS << formatv("{0:2}", json::Value(std::move(JO))) << "\n"; +} } // 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 @@ -57,12 +57,13 @@ #ifndef LLVM_TOOLS_LLVM_MCA_RESOURCEPRESSUREVIEW_H #define LLVM_TOOLS_LLVM_MCA_RESOURCEPRESSUREVIEW_H -#include "Views/View.h" +#include "Views/InstructionView.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/JSON.h" namespace llvm { namespace mca { @@ -70,6 +71,7 @@ /// 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 InstructionView { +protected: unsigned LastInstructionIdx; // Map to quickly obtain the ResourceUsage column index from a processor @@ -93,6 +95,19 @@ printResourcePressurePerIter(OS); printResourcePressurePerInst(OS); } + StringRef getNameAsString() const override { return "ResourcePressureView"; } +}; + +class ResourcePressureViewJSON : public ResourcePressureView { + json::Value toJSON() const; + +public: + ResourcePressureViewJSON(const llvm::MCSubtargetInfo &sti, + llvm::MCInstPrinter &Printer, + llvm::ArrayRef S) + : ResourcePressureView(sti, Printer, S) {} + + void printView(llvm::raw_ostream &OS) 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,36 @@ ++InstrIndex; } } + +json::Value ResourcePressureViewJSON::toJSON() const { + // We're dumping the instructions and the ResourceUsage array. + json::Array ResourcePressureInfo; + + // The ResourceUsage matrix is sparse, so we only consider + // non-zero values. + ArrayRef Source = getSource(); + const unsigned Executions = LastInstructionIdx / Source.size() + 1; + for (const auto &R : enumerate(ResourceUsage)) { + const ResourceCycles &RU = R.value(); + if (RU.getNumerator() == 0) + continue; + unsigned InstructionIndex = R.index() / NumResourceUnits; + unsigned ResourceIndex = R.index() % NumResourceUnits; + double Usage = RU / Executions; + ResourcePressureInfo.push_back( + json::Object({{"InstructionIndex", InstructionIndex}, + {"ResourceIndex", ResourceIndex}, + {"ResourceUsage", Usage}})); + } + + json::Object JO({{"ResourcePressureInfo", std::move(ResourcePressureInfo)}}); + return JO; +} + +void ResourcePressureViewJSON::printView(llvm::raw_ostream &OS) const { + json::Object JO; + JO.try_emplace(getNameAsString().str(), toJSON()); + OS << formatv("{0:2}", json::Value(std::move(JO))) << "\n"; +} } // 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 @@ -46,6 +46,7 @@ // The total number of micro opcodes contributed by a block of instructions. unsigned NumMicroOps; +protected: struct DisplayValues { unsigned Instructions; unsigned Iterations; @@ -87,8 +88,18 @@ void onCycleEnd() override { ++TotalCycles; } void onEvent(const HWInstructionEvent &Event) override; void printView(llvm::raw_ostream &OS) const override; + StringRef getNameAsString() const override { return "SummaryView"; } }; +class SummaryViewJSON : public SummaryView { + json::Value toJSON() const; + +public: + SummaryViewJSON(const llvm::MCSchedModel &Model, + llvm::ArrayRef S, unsigned Width) + : SummaryView(Model, S, Width) {} + void printView(llvm::raw_ostream &OS) const override; +}; } // namespace mca } // namespace llvm 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,25 @@ DV.BlockRThroughput = computeBlockRThroughput(SM, DispatchWidth, NumMicroOps, ProcResourceUsage); } + +json::Value SummaryViewJSON::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; +} + +void SummaryViewJSON::printView(raw_ostream &OS) const { + json::Object JO; + JO.try_emplace(getNameAsString().str(), toJSON()); + OS << formatv("{0:2}", json::Value(std::move(JO))) << "\n"; +} } // 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 @@ -100,12 +100,13 @@ #ifndef LLVM_TOOLS_LLVM_MCA_TIMELINEVIEW_H #define LLVM_TOOLS_LLVM_MCA_TIMELINEVIEW_H -#include "Views/View.h" +#include "Views/InstructionView.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/MC/MCInst.h" #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 { @@ -123,6 +124,7 @@ unsigned MaxCycle; unsigned LastCycle; +protected: struct TimelineViewEntry { int CycleDispatched; // A negative value is an "invalid cycle". unsigned CycleReady; @@ -178,6 +180,19 @@ printTimeline(OS); printAverageWaitTimes(OS); } + StringRef getNameAsString() const override { return "TimelineView"; } +}; + +class TimelineViewJSON : public TimelineView { + json::Value toJSON() const; + +public: + TimelineViewJSON(const llvm::MCSubtargetInfo &sti, + llvm::MCInstPrinter &Printer, llvm::ArrayRef S, + unsigned Iterations, unsigned Cycles) + : TimelineView(sti, Printer, S, Iterations, Cycles) {} + + void printView(llvm::raw_ostream &OS) 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,25 @@ } } } + +json::Value TimelineViewJSON::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)}}); +} + +void TimelineViewJSON::printView(llvm::raw_ostream &OS) const { + json::Object JO; + JO.try_emplace(getNameAsString().str(), toJSON()); + OS << formatv("{0:2}", json::Value(std::move(JO))) << "\n"; +} } // 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,35 +27,9 @@ public: virtual void printView(llvm::raw_ostream &OS) const = 0; virtual ~View() = default; + virtual StringRef getNameAsString() const = 0; void anchor() override; }; - -// The base class for views that deal with individual machine instructions. -class InstructionView : public View { - const llvm::MCSubtargetInfo &STI; - llvm::MCInstPrinter &MCIP; - llvm::ArrayRef Source; - - mutable std::string InstructionString; - mutable raw_string_ostream InstrStream; - -protected: - InstructionView(const llvm::MCSubtargetInfo &STI, - llvm::MCInstPrinter &Printer, - llvm::ArrayRef S) - : STI(STI), MCIP(Printer), Source(S), InstrStream(InstructionString) {} - - virtual ~InstructionView() = default; - - // Return a reference to a string representing a given machine instruction. - // 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; } -}; } // 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,18 +12,13 @@ //===----------------------------------------------------------------------===// #include "Views/View.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSubtargetInfo.h" namespace llvm { namespace mca { void View::anchor() {} -StringRef InstructionView::printInstructionString(const llvm::MCInst &MCI) const { - InstructionString = ""; - MCIP.printInst(&MCI, 0, "", STI, InstrStream); - InstrStream.flush(); - // Remove any tabs or spaces at the beginning of the instruction. - return StringRef(InstructionString).ltrim(); - } } // 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"), @@ -522,41 +527,66 @@ auto P = MCA.createDefaultPipeline(PO, S); mca::PipelinePrinter Printer(*P); - if (PrintSummaryView) + if (PrintJson) { + // Add the view that contains the instructions and CPU + // resource information. Printer.addView( - std::make_unique(SM, Insts, DispatchWidth)); - - if (EnableBottleneckAnalysis) { - Printer.addView(std::make_unique( - *STI, *IP, Insts, S.getNumIterations())); - } + std::make_unique(*STI, *IP, Insts, MCPU)); + if (PrintSummaryView) + Printer.addView( + std::make_unique(SM, Insts, DispatchWidth)); + if (PrintInstructionInfoView) + Printer.addView(std::make_unique( + *STI, *MCII, CE, ShowEncoding, Insts, *IP)); + if (PrintTimelineView) { + unsigned TimelineIterations = + TimelineMaxIterations ? TimelineMaxIterations : 10; + Printer.addView(std::make_unique( + *STI, *IP, Insts, + std::min(TimelineIterations, S.getNumIterations()), + TimelineMaxCycles)); + } + if (PrintResourcePressureView) + Printer.addView( + std::make_unique(*STI, *IP, Insts)); + } else { + if (PrintSummaryView) + Printer.addView( + std::make_unique(SM, Insts, DispatchWidth)); + + if (EnableBottleneckAnalysis) { + Printer.addView(std::make_unique( + *STI, *IP, Insts, S.getNumIterations())); + } - if (PrintInstructionInfoView) - Printer.addView(std::make_unique( - *STI, *MCII, CE, ShowEncoding, Insts, *IP)); + if (PrintInstructionInfoView) + Printer.addView(std::make_unique( + *STI, *MCII, CE, ShowEncoding, Insts, *IP)); - if (PrintDispatchStats) - Printer.addView(std::make_unique()); + if (PrintDispatchStats) + Printer.addView(std::make_unique()); - if (PrintSchedulerStats) - Printer.addView(std::make_unique(*STI)); + if (PrintSchedulerStats) + Printer.addView(std::make_unique(*STI)); - if (PrintRetireStats) - Printer.addView(std::make_unique(SM)); + if (PrintRetireStats) + Printer.addView(std::make_unique(SM)); - if (PrintRegisterFileStats) - Printer.addView(std::make_unique(*STI)); + if (PrintRegisterFileStats) + Printer.addView(std::make_unique(*STI)); - if (PrintResourcePressureView) - Printer.addView( - std::make_unique(*STI, *IP, Insts)); + if (PrintResourcePressureView) + Printer.addView( + std::make_unique(*STI, *IP, Insts)); - if (PrintTimelineView) { - unsigned TimelineIterations = - TimelineMaxIterations ? TimelineMaxIterations : 10; - Printer.addView(std::make_unique( - *STI, *IP, Insts, std::min(TimelineIterations, S.getNumIterations()), - TimelineMaxCycles)); + if (PrintTimelineView) { + unsigned TimelineIterations = + TimelineMaxIterations ? TimelineMaxIterations : 10; + Printer.addView(std::make_unique( + *STI, *IP, Insts, + std::min(TimelineIterations, S.getNumIterations()), + TimelineMaxCycles)); + } } if (!runPipeline(*P))