Skip to content

Commit 57cef58

Browse files
committed
[MCA] Moved the bottleneck analysis to its own file. NFCI
llvm-svn: 358554
1 parent e29874e commit 57cef58

File tree

6 files changed

+260
-154
lines changed

6 files changed

+260
-154
lines changed

llvm/tools/llvm-mca/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_llvm_tool(llvm-mca
1717
CodeRegion.cpp
1818
CodeRegionGenerator.cpp
1919
PipelinePrinter.cpp
20+
Views/BottleneckAnalysis.cpp
2021
Views/DispatchStatistics.cpp
2122
Views/InstructionInfoView.cpp
2223
Views/RegisterFileStatistics.cpp
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//===--------------------- BottleneckAnalysis.cpp ---------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
/// \file
9+
///
10+
/// This file implements the functionalities used by the BottleneckAnalysis
11+
/// to report bottleneck info.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "Views/BottleneckAnalysis.h"
16+
#include "llvm/ADT/SmallVector.h"
17+
#include "llvm/MCA/Support.h"
18+
#include "llvm/Support/Format.h"
19+
20+
namespace llvm {
21+
namespace mca {
22+
23+
#define DEBUG_TYPE "llvm-mca"
24+
25+
BottleneckAnalysis::BottleneckAnalysis(const MCSchedModel &Model)
26+
: SM(Model), TotalCycles(0), BPI({0, 0, 0, 0, 0}),
27+
ResourcePressureDistribution(Model.getNumProcResourceKinds(), 0),
28+
ProcResourceMasks(Model.getNumProcResourceKinds()),
29+
ResIdx2ProcResID(Model.getNumProcResourceKinds(), 0),
30+
PressureIncreasedBecauseOfResources(false),
31+
PressureIncreasedBecauseOfDataDependencies(false),
32+
SeenStallCycles(false) {
33+
computeProcResourceMasks(SM, ProcResourceMasks);
34+
for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {
35+
unsigned Index = getResourceStateIndex(ProcResourceMasks[I]);
36+
ResIdx2ProcResID[Index] = I;
37+
}
38+
}
39+
40+
void BottleneckAnalysis::onEvent(const HWPressureEvent &Event) {
41+
assert(Event.Reason != HWPressureEvent::INVALID &&
42+
"Unexpected invalid event!");
43+
44+
switch (Event.Reason) {
45+
default:
46+
break;
47+
48+
case HWPressureEvent::RESOURCES: {
49+
PressureIncreasedBecauseOfResources = true;
50+
++BPI.ResourcePressureCycles;
51+
uint64_t ResourceMask = Event.ResourceMask;
52+
while (ResourceMask) {
53+
uint64_t Current = ResourceMask & (-ResourceMask);
54+
unsigned Index = getResourceStateIndex(Current);
55+
unsigned ProcResID = ResIdx2ProcResID[Index];
56+
const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID);
57+
if (!PRDesc.SubUnitsIdxBegin) {
58+
ResourcePressureDistribution[Index]++;
59+
ResourceMask ^= Current;
60+
continue;
61+
}
62+
63+
for (unsigned I = 0, E = PRDesc.NumUnits; I < E; ++I) {
64+
unsigned OtherProcResID = PRDesc.SubUnitsIdxBegin[I];
65+
unsigned OtherMask = ProcResourceMasks[OtherProcResID];
66+
ResourcePressureDistribution[getResourceStateIndex(OtherMask)]++;
67+
}
68+
69+
ResourceMask ^= Current;
70+
}
71+
break;
72+
}
73+
74+
case HWPressureEvent::REGISTER_DEPS:
75+
PressureIncreasedBecauseOfDataDependencies = true;
76+
++BPI.RegisterDependencyCycles;
77+
break;
78+
case HWPressureEvent::MEMORY_DEPS:
79+
PressureIncreasedBecauseOfDataDependencies = true;
80+
++BPI.MemoryDependencyCycles;
81+
break;
82+
}
83+
}
84+
85+
void BottleneckAnalysis::printBottleneckHints(raw_ostream &OS) const {
86+
if (!SeenStallCycles || !BPI.PressureIncreaseCycles) {
87+
OS << "\nNo resource or data dependency bottlenecks discovered.\n";
88+
return;
89+
}
90+
91+
double PressurePerCycle =
92+
(double)BPI.PressureIncreaseCycles * 100 / TotalCycles;
93+
double ResourcePressurePerCycle =
94+
(double)BPI.ResourcePressureCycles * 100 / TotalCycles;
95+
double DDPerCycle = (double)BPI.DataDependencyCycles * 100 / TotalCycles;
96+
double RegDepPressurePerCycle =
97+
(double)BPI.RegisterDependencyCycles * 100 / TotalCycles;
98+
double MemDepPressurePerCycle =
99+
(double)BPI.MemoryDependencyCycles * 100 / TotalCycles;
100+
101+
OS << "\nCycles with backend pressure increase [ "
102+
<< format("%.2f", floor((PressurePerCycle * 100) + 0.5) / 100) << "% ]";
103+
104+
OS << "\nThroughput Bottlenecks: "
105+
<< "\n Resource Pressure [ "
106+
<< format("%.2f", floor((ResourcePressurePerCycle * 100) + 0.5) / 100)
107+
<< "% ]";
108+
109+
if (BPI.PressureIncreaseCycles) {
110+
for (unsigned I = 0, E = ResourcePressureDistribution.size(); I < E; ++I) {
111+
if (ResourcePressureDistribution[I]) {
112+
double Frequency =
113+
(double)ResourcePressureDistribution[I] * 100 / TotalCycles;
114+
unsigned Index = ResIdx2ProcResID[getResourceStateIndex(1ULL << I)];
115+
const MCProcResourceDesc &PRDesc = *SM.getProcResource(Index);
116+
OS << "\n - " << PRDesc.Name << " [ "
117+
<< format("%.2f", floor((Frequency * 100) + 0.5) / 100) << "% ]";
118+
}
119+
}
120+
}
121+
122+
OS << "\n Data Dependencies: [ "
123+
<< format("%.2f", floor((DDPerCycle * 100) + 0.5) / 100) << "% ]";
124+
125+
OS << "\n - Register Dependencies [ "
126+
<< format("%.2f", floor((RegDepPressurePerCycle * 100) + 0.5) / 100)
127+
<< "% ]";
128+
129+
OS << "\n - Memory Dependencies [ "
130+
<< format("%.2f", floor((MemDepPressurePerCycle * 100) + 0.5) / 100)
131+
<< "% ]\n\n";
132+
}
133+
134+
void BottleneckAnalysis::printView(raw_ostream &OS) const {
135+
std::string Buffer;
136+
raw_string_ostream TempStream(Buffer);
137+
printBottleneckHints(TempStream);
138+
TempStream.flush();
139+
OS << Buffer;
140+
}
141+
} // namespace mca.
142+
} // namespace llvm
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//===--------------------- BottleneckAnalysis.h -----------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
/// \file
9+
///
10+
/// This file implements the bottleneck analysis view.
11+
///
12+
/// This view internally observes backend pressure increase events in order to
13+
/// identify potential sources of bottlenecks.
14+
///
15+
/// Example of bottleneck analysis report:
16+
///
17+
/// Cycles with backend pressure increase [ 33.40% ]
18+
/// Throughput Bottlenecks:
19+
/// Resource Pressure [ 0.52% ]
20+
/// - JLAGU [ 0.52% ]
21+
/// Data Dependencies: [ 32.88% ]
22+
/// - Register Dependencies [ 32.88% ]
23+
/// - Memory Dependencies [ 0.00% ]
24+
///
25+
//===----------------------------------------------------------------------===//
26+
27+
#ifndef LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
28+
#define LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
29+
30+
#include "Views/View.h"
31+
#include "llvm/ADT/DenseMap.h"
32+
#include "llvm/MC/MCSchedule.h"
33+
#include "llvm/Support/raw_ostream.h"
34+
35+
namespace llvm {
36+
namespace mca {
37+
38+
/// A view that collects and prints a few performance numbers.
39+
class BottleneckAnalysis : public View {
40+
const llvm::MCSchedModel &SM;
41+
unsigned TotalCycles;
42+
43+
struct BackPressureInfo {
44+
// Cycles where backpressure increased.
45+
unsigned PressureIncreaseCycles;
46+
// Cycles where backpressure increased because of pipeline pressure.
47+
unsigned ResourcePressureCycles;
48+
// Cycles where backpressure increased because of data dependencies.
49+
unsigned DataDependencyCycles;
50+
// Cycles where backpressure increased because of register dependencies.
51+
unsigned RegisterDependencyCycles;
52+
// Cycles where backpressure increased because of memory dependencies.
53+
unsigned MemoryDependencyCycles;
54+
};
55+
BackPressureInfo BPI;
56+
57+
// Resource pressure distribution. There is an element for every processor
58+
// resource declared by the scheduling model. Quantities are number of cycles.
59+
llvm::SmallVector<unsigned, 8> ResourcePressureDistribution;
60+
61+
// Each processor resource is associated with a so-called processor resource
62+
// mask. This vector allows to correlate processor resource IDs with processor
63+
// resource masks. There is exactly one element per each processor resource
64+
// declared by the scheduling model.
65+
llvm::SmallVector<uint64_t, 8> ProcResourceMasks;
66+
67+
// Used to map resource indices to actual processor resource IDs.
68+
llvm::SmallVector<unsigned, 8> ResIdx2ProcResID;
69+
70+
// True if resource pressure events were notified during this cycle.
71+
bool PressureIncreasedBecauseOfResources;
72+
bool PressureIncreasedBecauseOfDataDependencies;
73+
74+
// True if throughput was affected by dispatch stalls.
75+
bool SeenStallCycles;
76+
77+
// Prints a bottleneck message to OS.
78+
void printBottleneckHints(llvm::raw_ostream &OS) const;
79+
80+
public:
81+
BottleneckAnalysis(const llvm::MCSchedModel &Model);
82+
83+
void onCycleEnd() override {
84+
++TotalCycles;
85+
if (PressureIncreasedBecauseOfResources ||
86+
PressureIncreasedBecauseOfDataDependencies) {
87+
++BPI.PressureIncreaseCycles;
88+
if (PressureIncreasedBecauseOfDataDependencies)
89+
++BPI.DataDependencyCycles;
90+
PressureIncreasedBecauseOfResources = false;
91+
PressureIncreasedBecauseOfDataDependencies = false;
92+
}
93+
}
94+
95+
void onEvent(const HWStallEvent &Event) override { SeenStallCycles = true; }
96+
97+
void onEvent(const HWPressureEvent &Event) override;
98+
99+
void printView(llvm::raw_ostream &OS) const override;
100+
};
101+
102+
} // namespace mca
103+
} // namespace llvm
104+
105+
#endif

llvm/tools/llvm-mca/Views/SummaryView.cpp

Lines changed: 4 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,13 @@ namespace mca {
2323
#define DEBUG_TYPE "llvm-mca"
2424

2525
SummaryView::SummaryView(const MCSchedModel &Model, ArrayRef<MCInst> S,
26-
unsigned Width, bool EmitBottleneckAnalysis)
26+
unsigned Width)
2727
: SM(Model), Source(S), DispatchWidth(Width?Width: Model.IssueWidth),
2828
LastInstructionIdx(0),
29-
TotalCycles(0), NumMicroOps(0), BPI({0, 0, 0, 0, 0}),
30-
ResourcePressureDistribution(Model.getNumProcResourceKinds(), 0),
29+
TotalCycles(0), NumMicroOps(0),
3130
ProcResourceUsage(Model.getNumProcResourceKinds(), 0),
3231
ProcResourceMasks(Model.getNumProcResourceKinds()),
33-
ResIdx2ProcResID(Model.getNumProcResourceKinds(), 0),
34-
PressureIncreasedBecauseOfResources(false),
35-
PressureIncreasedBecauseOfDataDependencies(false),
36-
SeenStallCycles(false),
37-
ShouldEmitBottleneckAnalysis(EmitBottleneckAnalysis) {
32+
ResIdx2ProcResID(Model.getNumProcResourceKinds(), 0) {
3833
computeProcResourceMasks(SM, ProcResourceMasks);
3934
for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {
4035
unsigned Index = getResourceStateIndex(ProcResourceMasks[I]);
@@ -67,100 +62,6 @@ void SummaryView::onEvent(const HWInstructionEvent &Event) {
6762
}
6863
}
6964

70-
void SummaryView::onEvent(const HWPressureEvent &Event) {
71-
assert(Event.Reason != HWPressureEvent::INVALID &&
72-
"Unexpected invalid event!");
73-
74-
switch (Event.Reason) {
75-
default:
76-
break;
77-
78-
case HWPressureEvent::RESOURCES: {
79-
PressureIncreasedBecauseOfResources = true;
80-
++BPI.ResourcePressureCycles;
81-
uint64_t ResourceMask = Event.ResourceMask;
82-
while (ResourceMask) {
83-
uint64_t Current = ResourceMask & (-ResourceMask);
84-
unsigned Index = getResourceStateIndex(Current);
85-
unsigned ProcResID = ResIdx2ProcResID[Index];
86-
const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID);
87-
if (!PRDesc.SubUnitsIdxBegin) {
88-
ResourcePressureDistribution[Index]++;
89-
ResourceMask ^= Current;
90-
continue;
91-
}
92-
93-
for (unsigned I = 0, E = PRDesc.NumUnits; I < E; ++I) {
94-
unsigned OtherProcResID = PRDesc.SubUnitsIdxBegin[I];
95-
unsigned OtherMask = ProcResourceMasks[OtherProcResID];
96-
ResourcePressureDistribution[getResourceStateIndex(OtherMask)]++;
97-
}
98-
99-
ResourceMask ^= Current;
100-
}
101-
}
102-
103-
break;
104-
case HWPressureEvent::REGISTER_DEPS:
105-
PressureIncreasedBecauseOfDataDependencies = true;
106-
++BPI.RegisterDependencyCycles;
107-
break;
108-
case HWPressureEvent::MEMORY_DEPS:
109-
PressureIncreasedBecauseOfDataDependencies = true;
110-
++BPI.MemoryDependencyCycles;
111-
break;
112-
}
113-
}
114-
115-
void SummaryView::printBottleneckHints(raw_ostream &OS) const {
116-
if (!SeenStallCycles || !BPI.PressureIncreaseCycles) {
117-
OS << "\nNo resource or data dependency bottlenecks discovered.\n";
118-
return;
119-
}
120-
121-
double PressurePerCycle =
122-
(double)BPI.PressureIncreaseCycles * 100 / TotalCycles;
123-
double ResourcePressurePerCycle =
124-
(double)BPI.ResourcePressureCycles * 100 / TotalCycles;
125-
double DDPerCycle = (double)BPI.DataDependencyCycles * 100 / TotalCycles;
126-
double RegDepPressurePerCycle =
127-
(double)BPI.RegisterDependencyCycles * 100 / TotalCycles;
128-
double MemDepPressurePerCycle =
129-
(double)BPI.MemoryDependencyCycles * 100 / TotalCycles;
130-
131-
OS << "\nCycles with backend pressure increase [ "
132-
<< format("%.2f", floor((PressurePerCycle * 100) + 0.5) / 100) << "% ]";
133-
134-
OS << "\nThroughput Bottlenecks: "
135-
<< "\n Resource Pressure [ "
136-
<< format("%.2f", floor((ResourcePressurePerCycle * 100) + 0.5) / 100)
137-
<< "% ]";
138-
139-
if (BPI.PressureIncreaseCycles) {
140-
for (unsigned I = 0, E = ResourcePressureDistribution.size(); I < E; ++I) {
141-
if (ResourcePressureDistribution[I]) {
142-
double Frequency =
143-
(double)ResourcePressureDistribution[I] * 100 / TotalCycles;
144-
unsigned Index = ResIdx2ProcResID[getResourceStateIndex(1ULL << I)];
145-
const MCProcResourceDesc &PRDesc = *SM.getProcResource(Index);
146-
OS << "\n - " << PRDesc.Name << " [ "
147-
<< format("%.2f", floor((Frequency * 100) + 0.5) / 100) << "% ]";
148-
}
149-
}
150-
}
151-
152-
OS << "\n Data Dependencies: [ "
153-
<< format("%.2f", floor((DDPerCycle * 100) + 0.5) / 100) << "% ]";
154-
155-
OS << "\n - Register Dependencies [ "
156-
<< format("%.2f", floor((RegDepPressurePerCycle * 100) + 0.5) / 100)
157-
<< "% ]";
158-
159-
OS << "\n - Memory Dependencies [ "
160-
<< format("%.2f", floor((MemDepPressurePerCycle * 100) + 0.5) / 100)
161-
<< "% ]\n\n";
162-
}
163-
16465
void SummaryView::printView(raw_ostream &OS) const {
16566
unsigned Instructions = Source.size();
16667
unsigned Iterations = (LastInstructionIdx / Instructions) + 1;
@@ -185,10 +86,9 @@ void SummaryView::printView(raw_ostream &OS) const {
18586
TempStream << "\nBlock RThroughput: "
18687
<< format("%.1f", floor((BlockRThroughput * 10) + 0.5) / 10)
18788
<< '\n';
188-
if (ShouldEmitBottleneckAnalysis)
189-
printBottleneckHints(TempStream);
19089
TempStream.flush();
19190
OS << Buffer;
19291
}
92+
19393
} // namespace mca.
19494
} // namespace llvm

0 commit comments

Comments
 (0)