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