mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-14 03:29:57 +00:00
[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.
This commit is contained in:
parent
922b26cde4
commit
d38be2ba0e
@ -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
|
||||
-----------
|
||||
|
@ -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
|
||||
---------------------------------
|
||||
|
||||
|
160
llvm/test/tools/llvm-mca/JSON/X86/views.s
Normal file
160
llvm/test/tools/llvm-mca/JSON/X86/views.s
Normal file
@ -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: }
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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 @@ public:
|
||||
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); }
|
||||
|
@ -78,6 +78,7 @@ public:
|
||||
printDispatchStalls(OS);
|
||||
printDispatchHistogram(OS);
|
||||
}
|
||||
StringRef getNameAsString() const override { return "DispatchStatistics"; }
|
||||
};
|
||||
} // namespace mca
|
||||
} // namespace llvm
|
||||
|
@ -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
|
||||
|
@ -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 @@ public:
|
||||
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
|
||||
|
60
llvm/tools/llvm-mca/Views/InstructionView.cpp
Normal file
60
llvm/tools/llvm-mca/Views/InstructionView.cpp
Normal file
@ -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
|
64
llvm/tools/llvm-mca/Views/InstructionView.h
Normal file
64
llvm/tools/llvm-mca/Views/InstructionView.h
Normal file
@ -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
|
@ -73,6 +73,9 @@ public:
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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 @@ public:
|
||||
printResourcePressurePerIter(OS);
|
||||
printResourcePressurePerInst(OS);
|
||||
}
|
||||
StringRef getNameAsString() const override { return "ResourcePressureView"; }
|
||||
json::Value toJSON() const;
|
||||
};
|
||||
} // namespace mca
|
||||
} // namespace llvm
|
||||
|
@ -52,6 +52,9 @@ public:
|
||||
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
|
||||
|
@ -88,6 +88,7 @@ public:
|
||||
llvm::ArrayRef<unsigned> Buffers) override;
|
||||
|
||||
void printView(llvm::raw_ostream &OS) const override;
|
||||
StringRef getNameAsString() const override { return "SchedulerStatistics"; }
|
||||
};
|
||||
} // namespace mca
|
||||
} // namespace llvm
|
||||
|
@ -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
|
||||
|
@ -87,8 +87,9 @@ public:
|
||||
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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 @@ public:
|
||||
printTimeline(OS);
|
||||
printAverageWaitTimes(OS);
|
||||
}
|
||||
StringRef getNameAsString() const override { return "TimelineView"; }
|
||||
json::Value toJSON() const;
|
||||
};
|
||||
} // namespace mca
|
||||
} // namespace llvm
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user