[llvm] d38be2b - [llvm-mca] Initial implementation of serialization using JSON. The views
Wolfgang Pieb via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 21 15:16:19 PST 2021
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(
More information about the llvm-commits
mailing list