xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===--------------------- ResourcePressureView.cpp -------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// This file implements methods in the ResourcePressureView interface.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "Views/ResourcePressureView.h"
150b57cec5SDimitry Andric #include "llvm/Support/FormattedStream.h"
160b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric namespace llvm {
190b57cec5SDimitry Andric namespace mca {
200b57cec5SDimitry Andric 
ResourcePressureView(const llvm::MCSubtargetInfo & sti,MCInstPrinter & Printer,ArrayRef<MCInst> S)210b57cec5SDimitry Andric ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti,
220b57cec5SDimitry Andric                                            MCInstPrinter &Printer,
230b57cec5SDimitry Andric                                            ArrayRef<MCInst> S)
24e8d8bef9SDimitry Andric     : InstructionView(sti, Printer, S), LastInstructionIdx(0) {
250b57cec5SDimitry Andric   // Populate the map of resource descriptors.
260b57cec5SDimitry Andric   unsigned R2VIndex = 0;
27e8d8bef9SDimitry Andric   const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
280b57cec5SDimitry Andric   for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
290b57cec5SDimitry Andric     const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
300b57cec5SDimitry Andric     unsigned NumUnits = ProcResource.NumUnits;
310b57cec5SDimitry Andric     // Skip groups and invalid resources with zero units.
320b57cec5SDimitry Andric     if (ProcResource.SubUnitsIdxBegin || !NumUnits)
330b57cec5SDimitry Andric       continue;
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric     Resource2VecIndex.insert(std::pair<unsigned, unsigned>(I, R2VIndex));
360b57cec5SDimitry Andric     R2VIndex += ProcResource.NumUnits;
370b57cec5SDimitry Andric   }
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   NumResourceUnits = R2VIndex;
40e8d8bef9SDimitry Andric   ResourceUsage.resize(NumResourceUnits * (getSource().size() + 1));
410b57cec5SDimitry Andric   std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0.0);
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
onEvent(const HWInstructionEvent & Event)440b57cec5SDimitry Andric void ResourcePressureView::onEvent(const HWInstructionEvent &Event) {
450b57cec5SDimitry Andric   if (Event.Type == HWInstructionEvent::Dispatched) {
460b57cec5SDimitry Andric     LastInstructionIdx = Event.IR.getSourceIndex();
470b57cec5SDimitry Andric     return;
480b57cec5SDimitry Andric   }
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   // We're only interested in Issue events.
510b57cec5SDimitry Andric   if (Event.Type != HWInstructionEvent::Issued)
520b57cec5SDimitry Andric     return;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event);
55e8d8bef9SDimitry Andric   ArrayRef<llvm::MCInst> Source = getSource();
560b57cec5SDimitry Andric   const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size();
57*5f757f3fSDimitry Andric   for (const std::pair<ResourceRef, ReleaseAtCycles> &Use :
580b57cec5SDimitry Andric        IssueEvent.UsedResources) {
590b57cec5SDimitry Andric     const ResourceRef &RR = Use.first;
6006c3fb27SDimitry Andric     assert(Resource2VecIndex.contains(RR.first));
610b57cec5SDimitry Andric     unsigned R2VIndex = Resource2VecIndex[RR.first];
6206c3fb27SDimitry Andric     R2VIndex += llvm::countr_zero(RR.second);
630b57cec5SDimitry Andric     ResourceUsage[R2VIndex + NumResourceUnits * SourceIdx] += Use.second;
640b57cec5SDimitry Andric     ResourceUsage[R2VIndex + NumResourceUnits * Source.size()] += Use.second;
650b57cec5SDimitry Andric   }
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric 
printColumnNames(formatted_raw_ostream & OS,const MCSchedModel & SM)680b57cec5SDimitry Andric static void printColumnNames(formatted_raw_ostream &OS,
690b57cec5SDimitry Andric                              const MCSchedModel &SM) {
700b57cec5SDimitry Andric   unsigned Column = OS.getColumn();
710b57cec5SDimitry Andric   for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
720b57cec5SDimitry Andric        I < E; ++I) {
730b57cec5SDimitry Andric     const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
740b57cec5SDimitry Andric     unsigned NumUnits = ProcResource.NumUnits;
750b57cec5SDimitry Andric     // Skip groups and invalid resources with zero units.
760b57cec5SDimitry Andric     if (ProcResource.SubUnitsIdxBegin || !NumUnits)
770b57cec5SDimitry Andric       continue;
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric     for (unsigned J = 0; J < NumUnits; ++J) {
800b57cec5SDimitry Andric       Column += 7;
810b57cec5SDimitry Andric       OS << "[" << ResourceIndex;
820b57cec5SDimitry Andric       if (NumUnits > 1)
830b57cec5SDimitry Andric         OS << '.' << J;
840b57cec5SDimitry Andric       OS << ']';
850b57cec5SDimitry Andric       OS.PadToColumn(Column);
860b57cec5SDimitry Andric     }
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric     ResourceIndex++;
890b57cec5SDimitry Andric   }
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric 
printResourcePressure(formatted_raw_ostream & OS,double Pressure,unsigned Col)920b57cec5SDimitry Andric static void printResourcePressure(formatted_raw_ostream &OS, double Pressure,
930b57cec5SDimitry Andric                                   unsigned Col) {
940b57cec5SDimitry Andric   if (!Pressure || Pressure < 0.005) {
950b57cec5SDimitry Andric     OS << " - ";
960b57cec5SDimitry Andric   } else {
970b57cec5SDimitry Andric     // Round to the value to the nearest hundredth and then print it.
980b57cec5SDimitry Andric     OS << format("%.2f", floor((Pressure * 100) + 0.5) / 100);
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric   OS.PadToColumn(Col);
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
printResourcePressurePerIter(raw_ostream & OS) const1030b57cec5SDimitry Andric void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const {
1040b57cec5SDimitry Andric   std::string Buffer;
1050b57cec5SDimitry Andric   raw_string_ostream TempStream(Buffer);
1060b57cec5SDimitry Andric   formatted_raw_ostream FOS(TempStream);
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric   FOS << "\n\nResources:\n";
109e8d8bef9SDimitry Andric   const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
1100b57cec5SDimitry Andric   for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
1110b57cec5SDimitry Andric        I < E; ++I) {
1120b57cec5SDimitry Andric     const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
1130b57cec5SDimitry Andric     unsigned NumUnits = ProcResource.NumUnits;
1140b57cec5SDimitry Andric     // Skip groups and invalid resources with zero units.
1150b57cec5SDimitry Andric     if (ProcResource.SubUnitsIdxBegin || !NumUnits)
1160b57cec5SDimitry Andric       continue;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric     for (unsigned J = 0; J < NumUnits; ++J) {
1190b57cec5SDimitry Andric       FOS << '[' << ResourceIndex;
1200b57cec5SDimitry Andric       if (NumUnits > 1)
1210b57cec5SDimitry Andric         FOS << '.' << J;
1220b57cec5SDimitry Andric       FOS << ']';
1230b57cec5SDimitry Andric       FOS.PadToColumn(6);
1240b57cec5SDimitry Andric       FOS << "- " << ProcResource.Name << '\n';
1250b57cec5SDimitry Andric     }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric     ResourceIndex++;
1280b57cec5SDimitry Andric   }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric   FOS << "\n\nResource pressure per iteration:\n";
1310b57cec5SDimitry Andric   FOS.flush();
1320b57cec5SDimitry Andric   printColumnNames(FOS, SM);
1330b57cec5SDimitry Andric   FOS << '\n';
1340b57cec5SDimitry Andric   FOS.flush();
1350b57cec5SDimitry Andric 
136e8d8bef9SDimitry Andric   ArrayRef<llvm::MCInst> Source = getSource();
1370b57cec5SDimitry Andric   const unsigned Executions = LastInstructionIdx / Source.size() + 1;
1380b57cec5SDimitry Andric   for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) {
1390b57cec5SDimitry Andric     double Usage = ResourceUsage[I + Source.size() * E];
1400b57cec5SDimitry Andric     printResourcePressure(FOS, Usage / Executions, (I + 1) * 7);
1410b57cec5SDimitry Andric   }
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   FOS.flush();
1440b57cec5SDimitry Andric   OS << Buffer;
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric 
printResourcePressurePerInst(raw_ostream & OS) const1470b57cec5SDimitry Andric void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {
1480b57cec5SDimitry Andric   std::string Buffer;
1490b57cec5SDimitry Andric   raw_string_ostream TempStream(Buffer);
1500b57cec5SDimitry Andric   formatted_raw_ostream FOS(TempStream);
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   FOS << "\n\nResource pressure by instruction:\n";
153e8d8bef9SDimitry Andric   printColumnNames(FOS, getSubTargetInfo().getSchedModel());
1540b57cec5SDimitry Andric   FOS << "Instructions:\n";
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   unsigned InstrIndex = 0;
157e8d8bef9SDimitry Andric   ArrayRef<llvm::MCInst> Source = getSource();
1580b57cec5SDimitry Andric   const unsigned Executions = LastInstructionIdx / Source.size() + 1;
1590b57cec5SDimitry Andric   for (const MCInst &MCI : Source) {
1600b57cec5SDimitry Andric     unsigned BaseEltIdx = InstrIndex * NumResourceUnits;
1610b57cec5SDimitry Andric     for (unsigned J = 0; J < NumResourceUnits; ++J) {
1620b57cec5SDimitry Andric       double Usage = ResourceUsage[J + BaseEltIdx];
1630b57cec5SDimitry Andric       printResourcePressure(FOS, Usage / Executions, (J + 1) * 7);
1640b57cec5SDimitry Andric     }
1650b57cec5SDimitry Andric 
166e8d8bef9SDimitry Andric     FOS << printInstructionString(MCI) << '\n';
1670b57cec5SDimitry Andric     FOS.flush();
1680b57cec5SDimitry Andric     OS << Buffer;
1690b57cec5SDimitry Andric     Buffer = "";
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric     ++InstrIndex;
1720b57cec5SDimitry Andric   }
1730b57cec5SDimitry Andric }
174e8d8bef9SDimitry Andric 
toJSON() const175e8d8bef9SDimitry Andric json::Value ResourcePressureView::toJSON() const {
176e8d8bef9SDimitry Andric   // We're dumping the instructions and the ResourceUsage array.
177e8d8bef9SDimitry Andric   json::Array ResourcePressureInfo;
178e8d8bef9SDimitry Andric 
179e8d8bef9SDimitry Andric   // The ResourceUsage matrix is sparse, so we only consider
180e8d8bef9SDimitry Andric   // non-zero values.
181e8d8bef9SDimitry Andric   ArrayRef<llvm::MCInst> Source = getSource();
182e8d8bef9SDimitry Andric   const unsigned Executions = LastInstructionIdx / Source.size() + 1;
183e8d8bef9SDimitry Andric   for (const auto &R : enumerate(ResourceUsage)) {
184*5f757f3fSDimitry Andric     const ReleaseAtCycles &RU = R.value();
185e8d8bef9SDimitry Andric     if (RU.getNumerator() == 0)
186e8d8bef9SDimitry Andric       continue;
187e8d8bef9SDimitry Andric     unsigned InstructionIndex = R.index() / NumResourceUnits;
188e8d8bef9SDimitry Andric     unsigned ResourceIndex = R.index() % NumResourceUnits;
189e8d8bef9SDimitry Andric     double Usage = RU / Executions;
190e8d8bef9SDimitry Andric     ResourcePressureInfo.push_back(
191e8d8bef9SDimitry Andric         json::Object({{"InstructionIndex", InstructionIndex},
192e8d8bef9SDimitry Andric                       {"ResourceIndex", ResourceIndex},
193e8d8bef9SDimitry Andric                       {"ResourceUsage", Usage}}));
194e8d8bef9SDimitry Andric   }
195e8d8bef9SDimitry Andric 
196e8d8bef9SDimitry Andric   json::Object JO({{"ResourcePressureInfo", std::move(ResourcePressureInfo)}});
197e8d8bef9SDimitry Andric   return JO;
198e8d8bef9SDimitry Andric }
1990b57cec5SDimitry Andric } // namespace mca
2000b57cec5SDimitry Andric } // namespace llvm
201