xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
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 
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 
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 
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 
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 
102 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 
145 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