1 //===--------------------- ResourcePressureView.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 methods in the ResourcePressureView interface.
11 ///
12 //===----------------------------------------------------------------------===//
13
14 #include "Views/ResourcePressureView.h"
15 #include "llvm/Support/FormattedStream.h"
16 #include "llvm/Support/raw_ostream.h"
17
18 namespace llvm {
19 namespace mca {
20
ResourcePressureView(const llvm::MCSubtargetInfo & sti,MCInstPrinter & Printer,ArrayRef<MCInst> S)21 ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti,
22 MCInstPrinter &Printer,
23 ArrayRef<MCInst> S)
24 : STI(sti), MCIP(Printer), Source(S), LastInstructionIdx(0) {
25 // Populate the map of resource descriptors.
26 unsigned R2VIndex = 0;
27 const MCSchedModel &SM = STI.getSchedModel();
28 for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
29 const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
30 unsigned NumUnits = ProcResource.NumUnits;
31 // Skip groups and invalid resources with zero units.
32 if (ProcResource.SubUnitsIdxBegin || !NumUnits)
33 continue;
34
35 Resource2VecIndex.insert(std::pair<unsigned, unsigned>(I, R2VIndex));
36 R2VIndex += ProcResource.NumUnits;
37 }
38
39 NumResourceUnits = R2VIndex;
40 ResourceUsage.resize(NumResourceUnits * (Source.size() + 1));
41 std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0.0);
42 }
43
onEvent(const HWInstructionEvent & Event)44 void ResourcePressureView::onEvent(const HWInstructionEvent &Event) {
45 if (Event.Type == HWInstructionEvent::Dispatched) {
46 LastInstructionIdx = Event.IR.getSourceIndex();
47 return;
48 }
49
50 // We're only interested in Issue events.
51 if (Event.Type != HWInstructionEvent::Issued)
52 return;
53
54 const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event);
55 const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size();
56 for (const std::pair<ResourceRef, ResourceCycles> &Use :
57 IssueEvent.UsedResources) {
58 const ResourceRef &RR = Use.first;
59 assert(Resource2VecIndex.find(RR.first) != Resource2VecIndex.end());
60 unsigned R2VIndex = Resource2VecIndex[RR.first];
61 R2VIndex += countTrailingZeros(RR.second);
62 ResourceUsage[R2VIndex + NumResourceUnits * SourceIdx] += Use.second;
63 ResourceUsage[R2VIndex + NumResourceUnits * Source.size()] += Use.second;
64 }
65 }
66
printColumnNames(formatted_raw_ostream & OS,const MCSchedModel & SM)67 static void printColumnNames(formatted_raw_ostream &OS,
68 const MCSchedModel &SM) {
69 unsigned Column = OS.getColumn();
70 for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
71 I < E; ++I) {
72 const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
73 unsigned NumUnits = ProcResource.NumUnits;
74 // Skip groups and invalid resources with zero units.
75 if (ProcResource.SubUnitsIdxBegin || !NumUnits)
76 continue;
77
78 for (unsigned J = 0; J < NumUnits; ++J) {
79 Column += 7;
80 OS << "[" << ResourceIndex;
81 if (NumUnits > 1)
82 OS << '.' << J;
83 OS << ']';
84 OS.PadToColumn(Column);
85 }
86
87 ResourceIndex++;
88 }
89 }
90
printResourcePressure(formatted_raw_ostream & OS,double Pressure,unsigned Col)91 static void printResourcePressure(formatted_raw_ostream &OS, double Pressure,
92 unsigned Col) {
93 if (!Pressure || Pressure < 0.005) {
94 OS << " - ";
95 } else {
96 // Round to the value to the nearest hundredth and then print it.
97 OS << format("%.2f", floor((Pressure * 100) + 0.5) / 100);
98 }
99 OS.PadToColumn(Col);
100 }
101
printResourcePressurePerIter(raw_ostream & OS) const102 void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const {
103 std::string Buffer;
104 raw_string_ostream TempStream(Buffer);
105 formatted_raw_ostream FOS(TempStream);
106
107 FOS << "\n\nResources:\n";
108 const MCSchedModel &SM = STI.getSchedModel();
109 for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
110 I < E; ++I) {
111 const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
112 unsigned NumUnits = ProcResource.NumUnits;
113 // Skip groups and invalid resources with zero units.
114 if (ProcResource.SubUnitsIdxBegin || !NumUnits)
115 continue;
116
117 for (unsigned J = 0; J < NumUnits; ++J) {
118 FOS << '[' << ResourceIndex;
119 if (NumUnits > 1)
120 FOS << '.' << J;
121 FOS << ']';
122 FOS.PadToColumn(6);
123 FOS << "- " << ProcResource.Name << '\n';
124 }
125
126 ResourceIndex++;
127 }
128
129 FOS << "\n\nResource pressure per iteration:\n";
130 FOS.flush();
131 printColumnNames(FOS, SM);
132 FOS << '\n';
133 FOS.flush();
134
135 const unsigned Executions = LastInstructionIdx / Source.size() + 1;
136 for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) {
137 double Usage = ResourceUsage[I + Source.size() * E];
138 printResourcePressure(FOS, Usage / Executions, (I + 1) * 7);
139 }
140
141 FOS.flush();
142 OS << Buffer;
143 }
144
printResourcePressurePerInst(raw_ostream & OS) const145 void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {
146 std::string Buffer;
147 raw_string_ostream TempStream(Buffer);
148 formatted_raw_ostream FOS(TempStream);
149
150 FOS << "\n\nResource pressure by instruction:\n";
151 printColumnNames(FOS, STI.getSchedModel());
152 FOS << "Instructions:\n";
153
154 std::string Instruction;
155 raw_string_ostream InstrStream(Instruction);
156
157 unsigned InstrIndex = 0;
158 const unsigned Executions = LastInstructionIdx / Source.size() + 1;
159 for (const MCInst &MCI : Source) {
160 unsigned BaseEltIdx = InstrIndex * NumResourceUnits;
161 for (unsigned J = 0; J < NumResourceUnits; ++J) {
162 double Usage = ResourceUsage[J + BaseEltIdx];
163 printResourcePressure(FOS, Usage / Executions, (J + 1) * 7);
164 }
165
166 MCIP.printInst(&MCI, 0, "", STI, InstrStream);
167 InstrStream.flush();
168 StringRef Str(Instruction);
169
170 // Remove any tabs or spaces at the beginning of the instruction.
171 Str = Str.ltrim();
172
173 FOS << Str << '\n';
174 Instruction = "";
175
176 FOS.flush();
177 OS << Buffer;
178 Buffer = "";
179
180 ++InstrIndex;
181 }
182 }
183 } // namespace mca
184 } // namespace llvm
185