llvm.org GIT mirror llvm / 430cf96
[MCA] Moved the bottleneck analysis to its own file. NFCI git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@358554 91177308-0d34-0410-b5e6-96231b3b80d8 Andrea Di Biagio 6 months ago
6 changed file(s) with 260 addition(s) and 154 deletion(s). Raw diff Collapse all Expand all
1616 CodeRegion.cpp
1717 CodeRegionGenerator.cpp
1818 PipelinePrinter.cpp
19 Views/BottleneckAnalysis.cpp
1920 Views/DispatchStatistics.cpp
2021 Views/InstructionInfoView.cpp
2122 Views/RegisterFileStatistics.cpp
0 //===--------------------- BottleneckAnalysis.cpp ---------------*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 /// \file
8 ///
9 /// This file implements the functionalities used by the BottleneckAnalysis
10 /// to report bottleneck info.
11 ///
12 //===----------------------------------------------------------------------===//
13
14 #include "Views/BottleneckAnalysis.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/MCA/Support.h"
17 #include "llvm/Support/Format.h"
18
19 namespace llvm {
20 namespace mca {
21
22 #define DEBUG_TYPE "llvm-mca"
23
24 BottleneckAnalysis::BottleneckAnalysis(const MCSchedModel &Model)
25 : SM(Model), TotalCycles(0), BPI({0, 0, 0, 0, 0}),
26 ResourcePressureDistribution(Model.getNumProcResourceKinds(), 0),
27 ProcResourceMasks(Model.getNumProcResourceKinds()),
28 ResIdx2ProcResID(Model.getNumProcResourceKinds(), 0),
29 PressureIncreasedBecauseOfResources(false),
30 PressureIncreasedBecauseOfDataDependencies(false),
31 SeenStallCycles(false) {
32 computeProcResourceMasks(SM, ProcResourceMasks);
33 for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {
34 unsigned Index = getResourceStateIndex(ProcResourceMasks[I]);
35 ResIdx2ProcResID[Index] = I;
36 }
37 }
38
39 void BottleneckAnalysis::onEvent(const HWPressureEvent &Event) {
40 assert(Event.Reason != HWPressureEvent::INVALID &&
41 "Unexpected invalid event!");
42
43 switch (Event.Reason) {
44 default:
45 break;
46
47 case HWPressureEvent::RESOURCES: {
48 PressureIncreasedBecauseOfResources = true;
49 ++BPI.ResourcePressureCycles;
50 uint64_t ResourceMask = Event.ResourceMask;
51 while (ResourceMask) {
52 uint64_t Current = ResourceMask & (-ResourceMask);
53 unsigned Index = getResourceStateIndex(Current);
54 unsigned ProcResID = ResIdx2ProcResID[Index];
55 const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID);
56 if (!PRDesc.SubUnitsIdxBegin) {
57 ResourcePressureDistribution[Index]++;
58 ResourceMask ^= Current;
59 continue;
60 }
61
62 for (unsigned I = 0, E = PRDesc.NumUnits; I < E; ++I) {
63 unsigned OtherProcResID = PRDesc.SubUnitsIdxBegin[I];
64 unsigned OtherMask = ProcResourceMasks[OtherProcResID];
65 ResourcePressureDistribution[getResourceStateIndex(OtherMask)]++;
66 }
67
68 ResourceMask ^= Current;
69 }
70 break;
71 }
72
73 case HWPressureEvent::REGISTER_DEPS:
74 PressureIncreasedBecauseOfDataDependencies = true;
75 ++BPI.RegisterDependencyCycles;
76 break;
77 case HWPressureEvent::MEMORY_DEPS:
78 PressureIncreasedBecauseOfDataDependencies = true;
79 ++BPI.MemoryDependencyCycles;
80 break;
81 }
82 }
83
84 void BottleneckAnalysis::printBottleneckHints(raw_ostream &OS) const {
85 if (!SeenStallCycles || !BPI.PressureIncreaseCycles) {
86 OS << "\nNo resource or data dependency bottlenecks discovered.\n";
87 return;
88 }
89
90 double PressurePerCycle =
91 (double)BPI.PressureIncreaseCycles * 100 / TotalCycles;
92 double ResourcePressurePerCycle =
93 (double)BPI.ResourcePressureCycles * 100 / TotalCycles;
94 double DDPerCycle = (double)BPI.DataDependencyCycles * 100 / TotalCycles;
95 double RegDepPressurePerCycle =
96 (double)BPI.RegisterDependencyCycles * 100 / TotalCycles;
97 double MemDepPressurePerCycle =
98 (double)BPI.MemoryDependencyCycles * 100 / TotalCycles;
99
100 OS << "\nCycles with backend pressure increase [ "
101 << format("%.2f", floor((PressurePerCycle * 100) + 0.5) / 100) << "% ]";
102
103 OS << "\nThroughput Bottlenecks: "
104 << "\n Resource Pressure [ "
105 << format("%.2f", floor((ResourcePressurePerCycle * 100) + 0.5) / 100)
106 << "% ]";
107
108 if (BPI.PressureIncreaseCycles) {
109 for (unsigned I = 0, E = ResourcePressureDistribution.size(); I < E; ++I) {
110 if (ResourcePressureDistribution[I]) {
111 double Frequency =
112 (double)ResourcePressureDistribution[I] * 100 / TotalCycles;
113 unsigned Index = ResIdx2ProcResID[getResourceStateIndex(1ULL << I)];
114 const MCProcResourceDesc &PRDesc = *SM.getProcResource(Index);
115 OS << "\n - " << PRDesc.Name << " [ "
116 << format("%.2f", floor((Frequency * 100) + 0.5) / 100) << "% ]";
117 }
118 }
119 }
120
121 OS << "\n Data Dependencies: [ "
122 << format("%.2f", floor((DDPerCycle * 100) + 0.5) / 100) << "% ]";
123
124 OS << "\n - Register Dependencies [ "
125 << format("%.2f", floor((RegDepPressurePerCycle * 100) + 0.5) / 100)
126 << "% ]";
127
128 OS << "\n - Memory Dependencies [ "
129 << format("%.2f", floor((MemDepPressurePerCycle * 100) + 0.5) / 100)
130 << "% ]\n\n";
131 }
132
133 void BottleneckAnalysis::printView(raw_ostream &OS) const {
134 std::string Buffer;
135 raw_string_ostream TempStream(Buffer);
136 printBottleneckHints(TempStream);
137 TempStream.flush();
138 OS << Buffer;
139 }
140 } // namespace mca.
141 } // namespace llvm
0 //===--------------------- BottleneckAnalysis.h -----------------*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 /// \file
8 ///
9 /// This file implements the bottleneck analysis view.
10 ///
11 /// This view internally observes backend pressure increase events in order to
12 /// identify potential sources of bottlenecks.
13 ///
14 /// Example of bottleneck analysis report:
15 ///
16 /// Cycles with backend pressure increase [ 33.40% ]
17 /// Throughput Bottlenecks:
18 /// Resource Pressure [ 0.52% ]
19 /// - JLAGU [ 0.52% ]
20 /// Data Dependencies: [ 32.88% ]
21 /// - Register Dependencies [ 32.88% ]
22 /// - Memory Dependencies [ 0.00% ]
23 ///
24 //===----------------------------------------------------------------------===//
25
26 #ifndef LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
27 #define LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
28
29 #include "Views/View.h"
30 #include "llvm/ADT/DenseMap.h"
31 #include "llvm/MC/MCSchedule.h"
32 #include "llvm/Support/raw_ostream.h"
33
34 namespace llvm {
35 namespace mca {
36
37 /// A view that collects and prints a few performance numbers.
38 class BottleneckAnalysis : public View {
39 const llvm::MCSchedModel &SM;
40 unsigned TotalCycles;
41
42 struct BackPressureInfo {
43 // Cycles where backpressure increased.
44 unsigned PressureIncreaseCycles;
45 // Cycles where backpressure increased because of pipeline pressure.
46 unsigned ResourcePressureCycles;
47 // Cycles where backpressure increased because of data dependencies.
48 unsigned DataDependencyCycles;
49 // Cycles where backpressure increased because of register dependencies.
50 unsigned RegisterDependencyCycles;
51 // Cycles where backpressure increased because of memory dependencies.
52 unsigned MemoryDependencyCycles;
53 };
54 BackPressureInfo BPI;
55
56 // Resource pressure distribution. There is an element for every processor
57 // resource declared by the scheduling model. Quantities are number of cycles.
58 llvm::SmallVector ResourcePressureDistribution;
59
60 // Each processor resource is associated with a so-called processor resource
61 // mask. This vector allows to correlate processor resource IDs with processor
62 // resource masks. There is exactly one element per each processor resource
63 // declared by the scheduling model.
64 llvm::SmallVector ProcResourceMasks;
65
66 // Used to map resource indices to actual processor resource IDs.
67 llvm::SmallVector ResIdx2ProcResID;
68
69 // True if resource pressure events were notified during this cycle.
70 bool PressureIncreasedBecauseOfResources;
71 bool PressureIncreasedBecauseOfDataDependencies;
72
73 // True if throughput was affected by dispatch stalls.
74 bool SeenStallCycles;
75
76 // Prints a bottleneck message to OS.
77 void printBottleneckHints(llvm::raw_ostream &OS) const;
78
79 public:
80 BottleneckAnalysis(const llvm::MCSchedModel &Model);
81
82 void onCycleEnd() override {
83 ++TotalCycles;
84 if (PressureIncreasedBecauseOfResources ||
85 PressureIncreasedBecauseOfDataDependencies) {
86 ++BPI.PressureIncreaseCycles;
87 if (PressureIncreasedBecauseOfDataDependencies)
88 ++BPI.DataDependencyCycles;
89 PressureIncreasedBecauseOfResources = false;
90 PressureIncreasedBecauseOfDataDependencies = false;
91 }
92 }
93
94 void onEvent(const HWStallEvent &Event) override { SeenStallCycles = true; }
95
96 void onEvent(const HWPressureEvent &Event) override;
97
98 void printView(llvm::raw_ostream &OS) const override;
99 };
100
101 } // namespace mca
102 } // namespace llvm
103
104 #endif
2222 #define DEBUG_TYPE "llvm-mca"
2323
2424 SummaryView::SummaryView(const MCSchedModel &Model, ArrayRef S,
25 unsigned Width, bool EmitBottleneckAnalysis)
25 unsigned Width)
2626 : SM(Model), Source(S), DispatchWidth(Width?Width: Model.IssueWidth),
2727 LastInstructionIdx(0),
28 TotalCycles(0), NumMicroOps(0), BPI({0, 0, 0, 0, 0}),
29 ResourcePressureDistribution(Model.getNumProcResourceKinds(), 0),
28 TotalCycles(0), NumMicroOps(0),
3029 ProcResourceUsage(Model.getNumProcResourceKinds(), 0),
3130 ProcResourceMasks(Model.getNumProcResourceKinds()),
32 ResIdx2ProcResID(Model.getNumProcResourceKinds(), 0),
33 PressureIncreasedBecauseOfResources(false),
34 PressureIncreasedBecauseOfDataDependencies(false),
35 SeenStallCycles(false),
36 ShouldEmitBottleneckAnalysis(EmitBottleneckAnalysis) {
31 ResIdx2ProcResID(Model.getNumProcResourceKinds(), 0) {
3732 computeProcResourceMasks(SM, ProcResourceMasks);
3833 for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {
3934 unsigned Index = getResourceStateIndex(ProcResourceMasks[I]);
6661 }
6762 }
6863
69 void SummaryView::onEvent(const HWPressureEvent &Event) {
70 assert(Event.Reason != HWPressureEvent::INVALID &&
71 "Unexpected invalid event!");
72
73 switch (Event.Reason) {
74 default:
75 break;
76
77 case HWPressureEvent::RESOURCES: {
78 PressureIncreasedBecauseOfResources = true;
79 ++BPI.ResourcePressureCycles;
80 uint64_t ResourceMask = Event.ResourceMask;
81 while (ResourceMask) {
82 uint64_t Current = ResourceMask & (-ResourceMask);
83 unsigned Index = getResourceStateIndex(Current);
84 unsigned ProcResID = ResIdx2ProcResID[Index];
85 const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID);
86 if (!PRDesc.SubUnitsIdxBegin) {
87 ResourcePressureDistribution[Index]++;
88 ResourceMask ^= Current;
89 continue;
90 }
91
92 for (unsigned I = 0, E = PRDesc.NumUnits; I < E; ++I) {
93 unsigned OtherProcResID = PRDesc.SubUnitsIdxBegin[I];
94 unsigned OtherMask = ProcResourceMasks[OtherProcResID];
95 ResourcePressureDistribution[getResourceStateIndex(OtherMask)]++;
96 }
97
98 ResourceMask ^= Current;
99 }
100 }
101
102 break;
103 case HWPressureEvent::REGISTER_DEPS:
104 PressureIncreasedBecauseOfDataDependencies = true;
105 ++BPI.RegisterDependencyCycles;
106 break;
107 case HWPressureEvent::MEMORY_DEPS:
108 PressureIncreasedBecauseOfDataDependencies = true;
109 ++BPI.MemoryDependencyCycles;
110 break;
111 }
112 }
113
114 void SummaryView::printBottleneckHints(raw_ostream &OS) const {
115 if (!SeenStallCycles || !BPI.PressureIncreaseCycles) {
116 OS << "\nNo resource or data dependency bottlenecks discovered.\n";
117 return;
118 }
119
120 double PressurePerCycle =
121 (double)BPI.PressureIncreaseCycles * 100 / TotalCycles;
122 double ResourcePressurePerCycle =
123 (double)BPI.ResourcePressureCycles * 100 / TotalCycles;
124 double DDPerCycle = (double)BPI.DataDependencyCycles * 100 / TotalCycles;
125 double RegDepPressurePerCycle =
126 (double)BPI.RegisterDependencyCycles * 100 / TotalCycles;
127 double MemDepPressurePerCycle =
128 (double)BPI.MemoryDependencyCycles * 100 / TotalCycles;
129
130 OS << "\nCycles with backend pressure increase [ "
131 << format("%.2f", floor((PressurePerCycle * 100) + 0.5) / 100) << "% ]";
132
133 OS << "\nThroughput Bottlenecks: "
134 << "\n Resource Pressure [ "
135 << format("%.2f", floor((ResourcePressurePerCycle * 100) + 0.5) / 100)
136 << "% ]";
137
138 if (BPI.PressureIncreaseCycles) {
139 for (unsigned I = 0, E = ResourcePressureDistribution.size(); I < E; ++I) {
140 if (ResourcePressureDistribution[I]) {
141 double Frequency =
142 (double)ResourcePressureDistribution[I] * 100 / TotalCycles;
143 unsigned Index = ResIdx2ProcResID[getResourceStateIndex(1ULL << I)];
144 const MCProcResourceDesc &PRDesc = *SM.getProcResource(Index);
145 OS << "\n - " << PRDesc.Name << " [ "
146 << format("%.2f", floor((Frequency * 100) + 0.5) / 100) << "% ]";
147 }
148 }
149 }
150
151 OS << "\n Data Dependencies: [ "
152 << format("%.2f", floor((DDPerCycle * 100) + 0.5) / 100) << "% ]";
153
154 OS << "\n - Register Dependencies [ "
155 << format("%.2f", floor((RegDepPressurePerCycle * 100) + 0.5) / 100)
156 << "% ]";
157
158 OS << "\n - Memory Dependencies [ "
159 << format("%.2f", floor((MemDepPressurePerCycle * 100) + 0.5) / 100)
160 << "% ]\n\n";
161 }
162
16364 void SummaryView::printView(raw_ostream &OS) const {
16465 unsigned Instructions = Source.size();
16566 unsigned Iterations = (LastInstructionIdx / Instructions) + 1;
18485 TempStream << "\nBlock RThroughput: "
18586 << format("%.1f", floor((BlockRThroughput * 10) + 0.5) / 10)
18687 << '\n';
187 if (ShouldEmitBottleneckAnalysis)
188 printBottleneckHints(TempStream);
18988 TempStream.flush();
19089 OS << Buffer;
19190 }
91
19292 } // namespace mca.
19393 } // namespace llvm
4545 // The total number of micro opcodes contributed by a block of instructions.
4646 unsigned NumMicroOps;
4747
48 struct BackPressureInfo {
49 // Cycles where backpressure increased.
50 unsigned PressureIncreaseCycles;
51 // Cycles where backpressure increased because of pipeline pressure.
52 unsigned ResourcePressureCycles;
53 // Cycles where backpressure increased because of data dependencies.
54 unsigned DataDependencyCycles;
55 // Cycles where backpressure increased because of register dependencies.
56 unsigned RegisterDependencyCycles;
57 // Cycles where backpressure increased because of memory dependencies.
58 unsigned MemoryDependencyCycles;
59 };
60 BackPressureInfo BPI;
61
62 // Resource pressure distribution. There is an element for every processor
63 // resource declared by the scheduling model. Quantities are number of cycles.
64 llvm::SmallVector ResourcePressureDistribution;
65
6648 // For each processor resource, this vector stores the cumulative number of
6749 // resource cycles consumed by the analyzed code block.
6850 llvm::SmallVector ProcResourceUsage;
7658 // Used to map resource indices to actual processor resource IDs.
7759 llvm::SmallVector ResIdx2ProcResID;
7860
79 // True if resource pressure events were notified during this cycle.
80 bool PressureIncreasedBecauseOfResources;
81 bool PressureIncreasedBecauseOfDataDependencies;
82
83 // True if throughput was affected by dispatch stalls.
84 bool SeenStallCycles;
85
86 // True if the bottleneck analysis should be displayed.
87 bool ShouldEmitBottleneckAnalysis;
88
8961 // Compute the reciprocal throughput for the analyzed code block.
9062 // The reciprocal block throughput is computed as the MAX between:
9163 // - NumMicroOps / DispatchWidth
9264 // - Total Resource Cycles / #Units (for every resource consumed).
9365 double getBlockRThroughput() const;
9466
95 // Prints a bottleneck message to OS.
96 void printBottleneckHints(llvm::raw_ostream &OS) const;
97
9867 public:
9968 SummaryView(const llvm::MCSchedModel &Model, llvm::ArrayRef S,
100 unsigned Width, bool EmitBottleneckAnalysis);
69 unsigned Width);
10170
102 void onCycleEnd() override {
103 ++TotalCycles;
104 if (PressureIncreasedBecauseOfResources ||
105 PressureIncreasedBecauseOfDataDependencies) {
106 ++BPI.PressureIncreaseCycles;
107 if (PressureIncreasedBecauseOfDataDependencies)
108 ++BPI.DataDependencyCycles;
109 PressureIncreasedBecauseOfResources = false;
110 PressureIncreasedBecauseOfDataDependencies = false;
111 }
112 }
71 void onCycleEnd() override { ++TotalCycles; }
11372 void onEvent(const HWInstructionEvent &Event) override;
114 void onEvent(const HWStallEvent &Event) override {
115 SeenStallCycles = true;
116 }
117
118 void onEvent(const HWPressureEvent &Event) override;
119
12073 void printView(llvm::raw_ostream &OS) const override;
12174 };
75
12276 } // namespace mca
12377 } // namespace llvm
12478
2222 #include "CodeRegion.h"
2323 #include "CodeRegionGenerator.h"
2424 #include "PipelinePrinter.h"
25 #include "Views/BottleneckAnalysis.h"
2526 #include "Views/DispatchStatistics.h"
2627 #include "Views/InstructionInfoView.h"
2728 #include "Views/RegisterFileStatistics.h"
476477
477478 if (PrintSummaryView)
478479 Printer.addView(llvm::make_unique(
479 SM, Insts, DispatchWidth, EnableBottleneckAnalysis));
480 SM, Insts, DispatchWidth));
481
482 if (EnableBottleneckAnalysis)
483 Printer.addView(llvm::make_unique(SM));
480484
481485 if (PrintInstructionInfoView)
482486 Printer.addView(