diff --git a/llvm/docs/CommandGuide/llvm-mca.rst b/llvm/docs/CommandGuide/llvm-mca.rst --- a/llvm/docs/CommandGuide/llvm-mca.rst +++ b/llvm/docs/CommandGuide/llvm-mca.rst @@ -128,7 +128,7 @@ Specify the size of the load queue in the load/store unit emulated by the tool. By default, the tool assumes an unbound number of entries in the load queue. A value of zero for this flag is ignored, and the default load queue size is - used instead. + used instead. .. option:: -squeue= @@ -203,16 +203,18 @@ .. option:: -bottleneck-analysis Print information about bottlenecks that affect the throughput. This analysis - can be expensive, and it is disabled by default. Bottlenecks are highlighted + can be expensive, and it is disabled by default. Bottlenecks are highlighted in the summary view. Bottleneck analysis is currently not supported for processors with an in-order backend. .. 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. - + Print the requested views in valid 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. However, not all views are + currently supported. For example, the report from the bottleneck analysis is + not printed out in JSON. All the default views are currently supported. + .. option:: -disable-cb Force usage of the generic CustomBehaviour class rather than using the target @@ -987,7 +989,7 @@ Custom Behaviour """""""""""""""""""""""""""""""""""" Due to certain instructions not being expressed perfectly within their -scheduling model, :program:`llvm-ma` isn't always able to simulate them +scheduling model, :program:`llvm-mca` isn't always able to simulate them perfectly. Modifying the scheduling model isn't always a viable option though (maybe because the instruction is modeled incorrectly on purpose or the instruction's behaviour is quite complex). The diff --git a/llvm/test/tools/llvm-mca/JSON/X86/views.s b/llvm/test/tools/llvm-mca/JSON/X86/views.s --- a/llvm/test/tools/llvm-mca/JSON/X86/views.s +++ b/llvm/test/tools/llvm-mca/JSON/X86/views.s @@ -2,7 +2,11 @@ # Verify that we create proper JSON for the MCA views TimelineView, ResourcePressureview, # InstructionInfoView and SummaryView. -# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=haswell --json --timeline-max-iterations=1 --timeline < %s | FileCheck %s +# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=haswell --json --timeline-max-iterations=1 --timeline --all-stats --all-views < %s | FileCheck %s +# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=haswell --json --timeline-max-iterations=1 --timeline --all-stats --all-views -o %t.json < %s +# RUN: cat %t.json \ +# RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ +# RUN: | FileCheck %s add %eax, %eax add %ebx, %ebx @@ -10,29 +14,122 @@ 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: "DispatchStatistics": { +# CHECK-NEXT: "GROUP": 0, +# CHECK-NEXT: "LQ": 0, +# CHECK-NEXT: "RAT": 0, +# CHECK-NEXT: "RCU": 0, +# CHECK-NEXT: "SCHEDQ": 0, +# CHECK-NEXT: "SQ": 0, +# CHECK-NEXT: "USH": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "InstructionInfoView": { +# CHECK-NEXT: "InstructionList": [ +# 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: { +# CHECK-NEXT: }, +# CHECK-NEXT: "Instructions and CPU resources": { +# 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: "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: "SummaryView": { # CHECK-NEXT: "BlockRThroughput": 1, # CHECK-NEXT: "DispatchWidth": 4, @@ -42,119 +139,37 @@ # 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: "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: "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/PipelinePrinter.cpp b/llvm/tools/llvm-mca/PipelinePrinter.cpp --- a/llvm/tools/llvm-mca/PipelinePrinter.cpp +++ b/llvm/tools/llvm-mca/PipelinePrinter.cpp @@ -18,8 +18,18 @@ namespace mca { void PipelinePrinter::printReport(llvm::raw_ostream &OS) const { - for (const auto &V : Views) - V->printView(OutputKind, OS); + json::Object JO; + for (const auto &V : Views) { + if ((OutputKind == View::OK_JSON)) { + if (V->isSerializable()) { + JO.try_emplace(V->getNameAsString().str(), V->toJSON()); + } + } else { + V->printView(OS); + } + } + if (OutputKind == View::OK_JSON) + OS << formatv("{0:2}", json::Value(std::move(JO))) << "\n"; } } // namespace mca. } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h b/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h --- a/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h +++ b/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h @@ -333,7 +333,7 @@ void printView(raw_ostream &OS) const override; StringRef getNameAsString() const override { return "BottleneckAnalysis"; } - json::Value toJSON() const override { return "not implemented"; } + bool isSerializable() const override { return false; } #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 --- a/llvm/tools/llvm-mca/Views/DispatchStatistics.h +++ b/llvm/tools/llvm-mca/Views/DispatchStatistics.h @@ -79,6 +79,7 @@ printDispatchHistogram(OS); } StringRef getNameAsString() const override { return "DispatchStatistics"; } + json::Value toJSON() const override; }; } // namespace mca } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp b/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp --- a/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp +++ b/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp @@ -84,5 +84,16 @@ OS << Buffer; } +json::Value DispatchStatistics::toJSON() const { + json::Object JO({{"RAT", HWStalls[HWStallEvent::RegisterFileStall]}, + {"RCU", HWStalls[HWStallEvent::RetireControlUnitStall]}, + {"SCHEDQ", HWStalls[HWStallEvent::SchedulerQueueFull]}, + {"LQ", HWStalls[HWStallEvent::LoadQueueFull]}, + {"SQ", HWStalls[HWStallEvent::StoreQueueFull]}, + {"GROUP", HWStalls[HWStallEvent::DispatchGroupStall]}, + {"USH", HWStalls[HWStallEvent::CustomBehaviourStall]}}); + return JO; +} + } // namespace mca } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp b/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp --- a/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp +++ b/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp @@ -147,7 +147,7 @@ JO.try_emplace("Instruction", (unsigned)I.index()); InstInfo.push_back(std::move(JO)); } - return json::Value(std::move(InstInfo)); + return json::Object({{"InstructionList", json::Value(std::move(InstInfo))}}); } } // namespace mca. } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h b/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h --- a/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h +++ b/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h @@ -76,6 +76,7 @@ StringRef getNameAsString() const override { return "RegisterFileStatistics"; } + bool isSerializable() const override { return false; } }; } // namespace mca } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h b/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h --- a/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h +++ b/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h @@ -55,6 +55,7 @@ StringRef getNameAsString() const override { return "RetireControlUnitStatistics"; } + bool isSerializable() const override { return false; } }; } // namespace mca diff --git a/llvm/tools/llvm-mca/Views/SchedulerStatistics.h b/llvm/tools/llvm-mca/Views/SchedulerStatistics.h --- a/llvm/tools/llvm-mca/Views/SchedulerStatistics.h +++ b/llvm/tools/llvm-mca/Views/SchedulerStatistics.h @@ -89,6 +89,7 @@ void printView(llvm::raw_ostream &OS) const override; StringRef getNameAsString() const override { return "SchedulerStatistics"; } + bool isSerializable() const override { return false; } }; } // namespace mca } // namespace llvm diff --git a/llvm/tools/llvm-mca/Views/View.h b/llvm/tools/llvm-mca/Views/View.h --- a/llvm/tools/llvm-mca/Views/View.h +++ b/llvm/tools/llvm-mca/Views/View.h @@ -43,6 +43,7 @@ virtual ~View() = default; virtual StringRef getNameAsString() const = 0; virtual json::Value toJSON() const { return "not implemented"; } + virtual bool isSerializable() const { return true; } void anchor() override; }; } // namespace mca