Author: Wolfgang Pieb Date: 2021-01-21T15:15:54-08:00 New Revision: d38be2ba0e4ebfed4c13ab79f3a8631011d185eb
URL: https://github.com/llvm/llvm-project/commit/d38be2ba0e4ebfed4c13ab79f3a8631011d185eb DIFF: https://github.com/llvm/llvm-project/commit/d38be2ba0e4ebfed4c13ab79f3a8631011d185eb.diff LOG: [llvm-mca] Initial implementation of serialization using JSON. The views implemented at this time are Summary, Timeline, ResourcePressure and InstructionInfo. Use --json on the command line to obtain JSON output. Added: llvm/test/tools/llvm-mca/JSON/X86/views.s llvm/tools/llvm-mca/Views/InstructionView.cpp llvm/tools/llvm-mca/Views/InstructionView.h Modified: llvm/docs/CommandGuide/llvm-mca.rst llvm/docs/ReleaseNotes.rst llvm/tools/llvm-mca/CMakeLists.txt llvm/tools/llvm-mca/PipelinePrinter.cpp llvm/tools/llvm-mca/PipelinePrinter.h llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp llvm/tools/llvm-mca/Views/BottleneckAnalysis.h llvm/tools/llvm-mca/Views/DispatchStatistics.h llvm/tools/llvm-mca/Views/InstructionInfoView.cpp llvm/tools/llvm-mca/Views/InstructionInfoView.h llvm/tools/llvm-mca/Views/RegisterFileStatistics.h llvm/tools/llvm-mca/Views/ResourcePressureView.cpp llvm/tools/llvm-mca/Views/ResourcePressureView.h llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h llvm/tools/llvm-mca/Views/SchedulerStatistics.h llvm/tools/llvm-mca/Views/SummaryView.cpp llvm/tools/llvm-mca/Views/SummaryView.h llvm/tools/llvm-mca/Views/TimelineView.cpp llvm/tools/llvm-mca/Views/TimelineView.h llvm/tools/llvm-mca/Views/View.cpp llvm/tools/llvm-mca/Views/View.h llvm/tools/llvm-mca/llvm-mca.cpp Removed: ################################################################################ diff --git a/llvm/docs/CommandGuide/llvm-mca.rst b/llvm/docs/CommandGuide/llvm-mca.rst index 092aa2beb6c6..1122cb1de974 100644 --- a/llvm/docs/CommandGuide/llvm-mca.rst +++ b/llvm/docs/CommandGuide/llvm-mca.rst @@ -206,6 +206,12 @@ option specifies "``-``", then the output will also be sent to standard output. 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 ----------- diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst index 37742d28ba47..de8431fe3908 100644 --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -182,6 +182,10 @@ Changes to the LLVM tools executed with no input files instead of reading an input from stdin. Reading from stdin can still be achieved by specifying `-` as an input file. +* llvm-mca supports serialization of the timeline and summary views. + The `--json` command line option prints a JSON representation of + these views to stdout. + Changes to LLDB --------------------------------- diff --git a/llvm/test/tools/llvm-mca/JSON/X86/views.s b/llvm/test/tools/llvm-mca/JSON/X86/views.s new file mode 100644 index 000000000000..ddfe724a10c4 --- /dev/null +++ b/llvm/test/tools/llvm-mca/JSON/X86/views.s @@ -0,0 +1,160 @@ +# 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: { +# 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: "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: { +# 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: } diff --git a/llvm/tools/llvm-mca/CMakeLists.txt b/llvm/tools/llvm-mca/CMakeLists.txt index 9918cd8c8dc6..9df1923a5bdc 100644 --- a/llvm/tools/llvm-mca/CMakeLists.txt +++ b/llvm/tools/llvm-mca/CMakeLists.txt @@ -19,6 +19,7 @@ add_llvm_tool(llvm-mca Views/BottleneckAnalysis.cpp Views/DispatchStatistics.cpp Views/InstructionInfoView.cpp + Views/InstructionView.cpp Views/RegisterFileStatistics.cpp Views/ResourcePressureView.cpp Views/RetireControlUnitStatistics.cpp diff --git a/llvm/tools/llvm-mca/PipelinePrinter.cpp b/llvm/tools/llvm-mca/PipelinePrinter.cpp index 90d468075996..e7dfbfdce26d 100644 --- a/llvm/tools/llvm-mca/PipelinePrinter.cpp +++ b/llvm/tools/llvm-mca/PipelinePrinter.cpp @@ -19,7 +19,7 @@ namespace mca { void PipelinePrinter::printReport(llvm::raw_ostream &OS) const { for (const auto &V : Views) - V->printView(OS); + V->printView(OutputKind, OS); } } // namespace mca. } // namespace llvm diff --git a/llvm/tools/llvm-mca/PipelinePrinter.h b/llvm/tools/llvm-mca/PipelinePrinter.h index 004309cd7b8e..ae18140d32b7 100644 --- a/llvm/tools/llvm-mca/PipelinePrinter.h +++ b/llvm/tools/llvm-mca/PipelinePrinter.h @@ -36,9 +36,11 @@ namespace mca { class PipelinePrinter { Pipeline &P; llvm::SmallVector<std::unique_ptr<View>, 8> Views; + View::OutputKind OutputKind; public: - PipelinePrinter(Pipeline &pipeline) : P(pipeline) {} + PipelinePrinter(Pipeline &pipeline, View::OutputKind OutputKind) + : P(pipeline), OutputKind(OutputKind) {} void addView(std::unique_ptr<View> V) { P.addEventListener(V.get()); diff --git a/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp b/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp index 519b928fda5d..38a8e2ef9c53 100644 --- a/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp +++ b/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp @@ -287,7 +287,6 @@ void BottleneckAnalysis::printInstruction(formatted_raw_ostream &FOS, const MCInst &MCI, bool UseDifferentColor) const { FOS.PadToColumn(14); - if (UseDifferentColor) FOS.changeColor(raw_ostream::CYAN, true, false); FOS << printInstructionString(MCI); diff --git a/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h b/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h index a0aad9faff40..427937d9e3d7 100644 --- a/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h +++ b/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,8 @@ class BottleneckAnalysis : public InstructionView { void onEvent(const HWInstructionEvent &Event) override; void printView(raw_ostream &OS) const override; + StringRef getNameAsString() const override { return "BottleneckAnalysis"; } + json::Value toJSON() const override { return "not implemented"; } #ifndef NDEBUG void dump(raw_ostream &OS, MCInstPrinter &MCIP) const { DG.dump(OS, MCIP); } diff --git a/llvm/tools/llvm-mca/Views/DispatchStatistics.h b/llvm/tools/llvm-mca/Views/DispatchStatistics.h index 07c0f5a4c68f..8d999fb0acfe 100644 --- a/llvm/tools/llvm-mca/Views/DispatchStatistics.h +++ b/llvm/tools/llvm-mca/Views/DispatchStatistics.h @@ -78,6 +78,7 @@ class DispatchStatistics : public View { printDispatchStalls(OS); printDispatchHistogram(OS); } + StringRef getNameAsString() const override { return "DispatchStatistics"; } }; } // namespace mca } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp b/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp index 803b3ec578aa..bff5729bbc96 100644 --- a/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp +++ b/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 { @@ -39,7 +40,7 @@ void InstructionInfoView::printView(raw_ostream &OS) const { TempStream << "\n[1] [2] [3] [4] [5] [6] Instructions:\n"; } - for (auto I : enumerate(zip(IIVD, Source))) { + for (const auto &I : enumerate(zip(IIVD, Source))) { const InstructionInfoViewData &IIVDEntry = std::get<0>(I.value()); TempStream << ' ' << IIVDEntry.NumMicroOpcodes << " "; @@ -92,7 +93,7 @@ void InstructionInfoView::collectData( MutableArrayRef<InstructionInfoViewData> IIVD) const { const llvm::MCSubtargetInfo &STI = getSubTargetInfo(); const MCSchedModel &SM = STI.getSchedModel(); - for (auto I : zip(getSource(), IIVD)) { + for (const auto &I : zip(getSource(), IIVD)) { const MCInst &Inst = std::get<0>(I); InstructionInfoViewData &IIVDEntry = std::get<1>(I); const MCInstrDesc &MCDesc = MCII.get(Inst.getOpcode()); @@ -118,5 +119,35 @@ void InstructionInfoView::collectData( 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<llvm::MCInst> 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 diff --git a/llvm/tools/llvm-mca/Views/InstructionInfoView.h b/llvm/tools/llvm-mca/Views/InstructionInfoView.h index c2093b2d0429..82b2d678ea6b 100644 --- a/llvm/tools/llvm-mca/Views/InstructionInfoView.h +++ b/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" @@ -77,6 +77,9 @@ class InstructionInfoView : public InstructionView { PrintEncodings(ShouldPrintEncodings) {} void printView(llvm::raw_ostream &OS) const override; + StringRef getNameAsString() const override { return "InstructionInfoView"; } + json::Value toJSON() const; + json::Object toJSON(const InstructionInfoViewData &IIVD) const; }; } // namespace mca } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/InstructionView.cpp b/llvm/tools/llvm-mca/Views/InstructionView.cpp new file mode 100644 index 000000000000..7f7a5b7cdbbb --- /dev/null +++ b/llvm/tools/llvm-mca/Views/InstructionView.cpp @@ -0,0 +1,60 @@ +//===----------------------- View.cpp ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines the member functions of the class InstructionView. +/// +//===----------------------------------------------------------------------===// + +#include <sstream> +#include "Views/InstructionView.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSubtargetInfo.h" + +namespace llvm { +namespace mca { + +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(); +} + +json::Value InstructionView::toJSON() const { + json::Object JO; + json::Array SourceInfo; + for (const auto &MCI : getSource()) { + StringRef Instruction = printInstructionString(MCI); + SourceInfo.push_back(Instruction.str()); + } + JO.try_emplace("Instructions", std::move(SourceInfo)); + + json::Array Resources; + const MCSchedModel &SM = STI.getSchedModel(); + for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) { + const MCProcResourceDesc &ProcResource = *SM.getProcResource(I); + unsigned NumUnits = ProcResource.NumUnits; + // Skip groups and invalid resources with zero units. + if (ProcResource.SubUnitsIdxBegin || !NumUnits) + continue; + for (unsigned J = 0; J < NumUnits; ++J) { + std::stringstream ResNameStream; + ResNameStream << ProcResource.Name; + if (NumUnits > 1) + ResNameStream << "." << J; + Resources.push_back(ResNameStream.str()); + } + } + JO.try_emplace("Resources", json::Object({{"CPUName", MCPU}, {"Resources", std::move(Resources)}})); + + return JO; +} +} // namespace mca +} // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/InstructionView.h b/llvm/tools/llvm-mca/Views/InstructionView.h new file mode 100644 index 000000000000..3f967471fabe --- /dev/null +++ b/llvm/tools/llvm-mca/Views/InstructionView.h @@ -0,0 +1,64 @@ +//===----------------------- InstrucionView.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines the main interface for Views that examine and reference +/// a sequence of machine instructions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_MCA_INSTRUCTIONVIEW_H +#define LLVM_TOOLS_LLVM_MCA_INSTRUCTIONVIEW_H + +#include "Views/View.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/JSON.h" + +namespace llvm { +namespace mca { + +// The base class for views that deal with individual machine instructions. +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; + +public: + void printView(llvm::raw_ostream &) const {} + 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) {} + + virtual ~InstructionView() = default; + + StringRef getNameAsString() const { return "Instructions and CPU resources"; } + // 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<llvm::MCInst> getSource() const { return Source; } + json::Value toJSON() const override; + virtual void printViewJSON(llvm::raw_ostream &OS) override { + json::Value JV = toJSON(); + OS << formatv("{0:2}", JV) << "\n"; + } +}; +} // namespace mca +} // namespace llvm + +#endif diff --git a/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h b/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h index a2273dd48b22..cf384dbfe337 100644 --- a/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h +++ b/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h @@ -73,6 +73,9 @@ class RegisterFileStatistics : public View { 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 diff --git a/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp b/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp index a5a74210c672..77b3ba0b7c8d 100644 --- a/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp +++ b/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp @@ -171,5 +171,30 @@ void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const { ++InstrIndex; } } + +json::Value ResourcePressureView::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<llvm::MCInst> 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; +} } // namespace mca } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/ResourcePressureView.h b/llvm/tools/llvm-mca/Views/ResourcePressureView.h index 39914f9e2f27..5a9b5caee503 100644 --- a/llvm/tools/llvm-mca/Views/ResourcePressureView.h +++ b/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 { @@ -93,6 +94,8 @@ class ResourcePressureView : public InstructionView { printResourcePressurePerIter(OS); printResourcePressurePerInst(OS); } + StringRef getNameAsString() const override { return "ResourcePressureView"; } + json::Value toJSON() const; }; } // namespace mca } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h b/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h index 1a4d3dec5c56..662a223662e6 100644 --- a/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h +++ b/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h @@ -52,6 +52,9 @@ class RetireControlUnitStatistics : public View { 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 diff --git a/llvm/tools/llvm-mca/Views/SchedulerStatistics.h b/llvm/tools/llvm-mca/Views/SchedulerStatistics.h index 32711b4483b4..734046c3112f 100644 --- a/llvm/tools/llvm-mca/Views/SchedulerStatistics.h +++ b/llvm/tools/llvm-mca/Views/SchedulerStatistics.h @@ -88,6 +88,7 @@ class SchedulerStatistics final : public View { llvm::ArrayRef<unsigned> Buffers) override; void printView(llvm::raw_ostream &OS) const override; + StringRef getNameAsString() const override { return "SchedulerStatistics"; } }; } // namespace mca } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/SummaryView.cpp b/llvm/tools/llvm-mca/Views/SummaryView.cpp index e15b1b4cd7a0..c0fe3b5193a7 100644 --- a/llvm/tools/llvm-mca/Views/SummaryView.cpp +++ b/llvm/tools/llvm-mca/Views/SummaryView.cpp @@ -96,5 +96,19 @@ void SummaryView::collectData(DisplayValues &DV) const { 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 diff --git a/llvm/tools/llvm-mca/Views/SummaryView.h b/llvm/tools/llvm-mca/Views/SummaryView.h index bc957ea9152b..2622e869ef23 100644 --- a/llvm/tools/llvm-mca/Views/SummaryView.h +++ b/llvm/tools/llvm-mca/Views/SummaryView.h @@ -87,8 +87,9 @@ class SummaryView : public View { 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 } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/TimelineView.cpp b/llvm/tools/llvm-mca/Views/TimelineView.cpp index f520c5c31d3f..c8b481bc7ce6 100644 --- a/llvm/tools/llvm-mca/Views/TimelineView.cpp +++ b/llvm/tools/llvm-mca/Views/TimelineView.cpp @@ -297,5 +297,19 @@ void TimelineView::printTimeline(raw_ostream &OS) const { } } } + +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 diff --git a/llvm/tools/llvm-mca/Views/TimelineView.h b/llvm/tools/llvm-mca/Views/TimelineView.h index 528579edf708..a9e94d7b2a92 100644 --- a/llvm/tools/llvm-mca/Views/TimelineView.h +++ b/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 { @@ -178,6 +179,8 @@ class TimelineView : public InstructionView { printTimeline(OS); printAverageWaitTimes(OS); } + StringRef getNameAsString() const override { return "TimelineView"; } + json::Value toJSON() const; }; } // namespace mca } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/View.cpp b/llvm/tools/llvm-mca/Views/View.cpp index 4cef7456f366..09d08d3ae007 100644 --- a/llvm/tools/llvm-mca/Views/View.cpp +++ b/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 diff --git a/llvm/tools/llvm-mca/Views/View.h b/llvm/tools/llvm-mca/Views/View.h index 1af6e5959f31..85464bfda662 100644 --- a/llvm/tools/llvm-mca/Views/View.h +++ b/llvm/tools/llvm-mca/Views/View.h @@ -18,43 +18,33 @@ #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 { 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 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 json::Value toJSON() const { return "not implemented"; } 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<llvm::MCInst> Source; - - mutable std::string InstructionString; - mutable raw_string_ostream InstrStream; - -protected: - InstructionView(const llvm::MCSubtargetInfo &STI, - llvm::MCInstPrinter &Printer, - llvm::ArrayRef<llvm::MCInst> 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<llvm::MCInst> getSource() const { return Source; } -}; } // namespace mca } // namespace llvm diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp index d122e641ad25..13a2c6363579 100644 --- a/llvm/tools/llvm-mca/llvm-mca.cpp +++ b/llvm/tools/llvm-mca/llvm-mca.cpp @@ -96,6 +96,11 @@ static cl::opt<std::string> cl::desc("Additional target features."), cl::cat(ToolOptions)); +static cl::opt<bool> + PrintJson("json", + cl::desc("Print the output in json format"), + cl::cat(ToolOptions), cl::init(false)); + static cl::opt<int> OutputAsmVariant("output-asm-variant", cl::desc("Syntax variant to use for output printing"), @@ -501,7 +506,7 @@ 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, mca::View::OK_READABLE); // Create the views for this pipeline, execute, and emit a report. if (PrintInstructionInfoView) { @@ -520,7 +525,14 @@ int main(int argc, char **argv) { // Create a basic pipeline simulating an out-of-order backend. auto P = MCA.createDefaultPipeline(PO, S); - mca::PipelinePrinter Printer(*P); + mca::PipelinePrinter Printer(*P, PrintJson ? mca::View::OK_JSON + : mca::View::OK_READABLE); + + // When we output JSON, we add a view that contains the instructions + // and CPU resource information. + if (PrintJson) + Printer.addView( + std::make_unique<mca::InstructionView>(*STI, *IP, Insts, MCPU)); if (PrintSummaryView) Printer.addView( _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits