xref: /llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp (revision 85e3875ad7461fa8320db6895e0189cffb91ae7d)
110aa09f0SMatt Davis //===--------------------- ResourcePressureView.cpp -------------*- C++ -*-===//
210aa09f0SMatt Davis //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610aa09f0SMatt Davis //
710aa09f0SMatt Davis //===----------------------------------------------------------------------===//
810aa09f0SMatt Davis /// \file
910aa09f0SMatt Davis ///
1010aa09f0SMatt Davis /// This file implements methods in the ResourcePressureView interface.
1110aa09f0SMatt Davis ///
1210aa09f0SMatt Davis //===----------------------------------------------------------------------===//
1310aa09f0SMatt Davis 
1410aa09f0SMatt Davis #include "Views/ResourcePressureView.h"
1510aa09f0SMatt Davis #include "llvm/Support/FormattedStream.h"
1610aa09f0SMatt Davis #include "llvm/Support/raw_ostream.h"
1710aa09f0SMatt Davis 
185a8fd657SFangrui Song namespace llvm {
1910aa09f0SMatt Davis namespace mca {
2010aa09f0SMatt Davis 
ResourcePressureView(const llvm::MCSubtargetInfo & sti,MCInstPrinter & Printer,ArrayRef<MCInst> S)2177c26aebSAndrea Di Biagio ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti,
2284d00513SAndrea Di Biagio                                            MCInstPrinter &Printer,
2384d00513SAndrea Di Biagio                                            ArrayRef<MCInst> S)
24e02920feSWolfgang Pieb     : InstructionView(sti, Printer, S), LastInstructionIdx(0) {
2510aa09f0SMatt Davis   // Populate the map of resource descriptors.
2610aa09f0SMatt Davis   unsigned R2VIndex = 0;
27e02920feSWolfgang Pieb   const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
2810aa09f0SMatt Davis   for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
2910aa09f0SMatt Davis     const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
3010aa09f0SMatt Davis     unsigned NumUnits = ProcResource.NumUnits;
3110aa09f0SMatt Davis     // Skip groups and invalid resources with zero units.
3210aa09f0SMatt Davis     if (ProcResource.SubUnitsIdxBegin || !NumUnits)
3310aa09f0SMatt Davis       continue;
3410aa09f0SMatt Davis 
3510aa09f0SMatt Davis     Resource2VecIndex.insert(std::pair<unsigned, unsigned>(I, R2VIndex));
3610aa09f0SMatt Davis     R2VIndex += ProcResource.NumUnits;
3710aa09f0SMatt Davis   }
3810aa09f0SMatt Davis 
3910aa09f0SMatt Davis   NumResourceUnits = R2VIndex;
40e02920feSWolfgang Pieb   ResourceUsage.resize(NumResourceUnits * (getSource().size() + 1));
4110aa09f0SMatt Davis   std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0.0);
4210aa09f0SMatt Davis }
4310aa09f0SMatt Davis 
onEvent(const HWInstructionEvent & Event)4410aa09f0SMatt Davis void ResourcePressureView::onEvent(const HWInstructionEvent &Event) {
4584d00513SAndrea Di Biagio   if (Event.Type == HWInstructionEvent::Dispatched) {
4684d00513SAndrea Di Biagio     LastInstructionIdx = Event.IR.getSourceIndex();
4784d00513SAndrea Di Biagio     return;
4884d00513SAndrea Di Biagio   }
4984d00513SAndrea Di Biagio 
5010aa09f0SMatt Davis   // We're only interested in Issue events.
5110aa09f0SMatt Davis   if (Event.Type != HWInstructionEvent::Issued)
5210aa09f0SMatt Davis     return;
5384d00513SAndrea Di Biagio 
5410aa09f0SMatt Davis   const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event);
55e02920feSWolfgang Pieb   ArrayRef<llvm::MCInst> Source = getSource();
5610aa09f0SMatt Davis   const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size();
57*85e3875aSMichael Maitland   for (const std::pair<ResourceRef, ReleaseAtCycles> &Use :
58db834837SMatt Davis        IssueEvent.UsedResources) {
5910aa09f0SMatt Davis     const ResourceRef &RR = Use.first;
60398af9b4SKazu Hirata     assert(Resource2VecIndex.contains(RR.first));
6110aa09f0SMatt Davis     unsigned R2VIndex = Resource2VecIndex[RR.first];
6255e2cd16SKazu Hirata     R2VIndex += llvm::countr_zero(RR.second);
6310aa09f0SMatt Davis     ResourceUsage[R2VIndex + NumResourceUnits * SourceIdx] += Use.second;
6410aa09f0SMatt Davis     ResourceUsage[R2VIndex + NumResourceUnits * Source.size()] += Use.second;
6510aa09f0SMatt Davis   }
6610aa09f0SMatt Davis }
6710aa09f0SMatt Davis 
printColumnNames(formatted_raw_ostream & OS,const MCSchedModel & SM)6810aa09f0SMatt Davis static void printColumnNames(formatted_raw_ostream &OS,
6910aa09f0SMatt Davis                              const MCSchedModel &SM) {
7010aa09f0SMatt Davis   unsigned Column = OS.getColumn();
7110aa09f0SMatt Davis   for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
7210aa09f0SMatt Davis        I < E; ++I) {
7310aa09f0SMatt Davis     const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
7410aa09f0SMatt Davis     unsigned NumUnits = ProcResource.NumUnits;
7510aa09f0SMatt Davis     // Skip groups and invalid resources with zero units.
7610aa09f0SMatt Davis     if (ProcResource.SubUnitsIdxBegin || !NumUnits)
7710aa09f0SMatt Davis       continue;
7810aa09f0SMatt Davis 
7910aa09f0SMatt Davis     for (unsigned J = 0; J < NumUnits; ++J) {
8010aa09f0SMatt Davis       Column += 7;
8110aa09f0SMatt Davis       OS << "[" << ResourceIndex;
8210aa09f0SMatt Davis       if (NumUnits > 1)
8310aa09f0SMatt Davis         OS << '.' << J;
8410aa09f0SMatt Davis       OS << ']';
8510aa09f0SMatt Davis       OS.PadToColumn(Column);
8610aa09f0SMatt Davis     }
8710aa09f0SMatt Davis 
8810aa09f0SMatt Davis     ResourceIndex++;
8910aa09f0SMatt Davis   }
9010aa09f0SMatt Davis }
9110aa09f0SMatt Davis 
printResourcePressure(formatted_raw_ostream & OS,double Pressure,unsigned Col)9210aa09f0SMatt Davis static void printResourcePressure(formatted_raw_ostream &OS, double Pressure,
9310aa09f0SMatt Davis                                   unsigned Col) {
9410aa09f0SMatt Davis   if (!Pressure || Pressure < 0.005) {
9510aa09f0SMatt Davis     OS << " - ";
9610aa09f0SMatt Davis   } else {
9710aa09f0SMatt Davis     // Round to the value to the nearest hundredth and then print it.
9810aa09f0SMatt Davis     OS << format("%.2f", floor((Pressure * 100) + 0.5) / 100);
9910aa09f0SMatt Davis   }
10010aa09f0SMatt Davis   OS.PadToColumn(Col);
10110aa09f0SMatt Davis }
10210aa09f0SMatt Davis 
printResourcePressurePerIter(raw_ostream & OS) const10377c26aebSAndrea Di Biagio void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const {
10410aa09f0SMatt Davis   std::string Buffer;
10510aa09f0SMatt Davis   raw_string_ostream TempStream(Buffer);
10610aa09f0SMatt Davis   formatted_raw_ostream FOS(TempStream);
10710aa09f0SMatt Davis 
10810aa09f0SMatt Davis   FOS << "\n\nResources:\n";
109e02920feSWolfgang Pieb   const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
11010aa09f0SMatt Davis   for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
11110aa09f0SMatt Davis        I < E; ++I) {
11210aa09f0SMatt Davis     const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
11310aa09f0SMatt Davis     unsigned NumUnits = ProcResource.NumUnits;
11410aa09f0SMatt Davis     // Skip groups and invalid resources with zero units.
11510aa09f0SMatt Davis     if (ProcResource.SubUnitsIdxBegin || !NumUnits)
11610aa09f0SMatt Davis       continue;
11710aa09f0SMatt Davis 
11810aa09f0SMatt Davis     for (unsigned J = 0; J < NumUnits; ++J) {
11910aa09f0SMatt Davis       FOS << '[' << ResourceIndex;
12010aa09f0SMatt Davis       if (NumUnits > 1)
12110aa09f0SMatt Davis         FOS << '.' << J;
12210aa09f0SMatt Davis       FOS << ']';
12310aa09f0SMatt Davis       FOS.PadToColumn(6);
12410aa09f0SMatt Davis       FOS << "- " << ProcResource.Name << '\n';
12510aa09f0SMatt Davis     }
12610aa09f0SMatt Davis 
12710aa09f0SMatt Davis     ResourceIndex++;
12810aa09f0SMatt Davis   }
12910aa09f0SMatt Davis 
13010aa09f0SMatt Davis   FOS << "\n\nResource pressure per iteration:\n";
13110aa09f0SMatt Davis   FOS.flush();
13210aa09f0SMatt Davis   printColumnNames(FOS, SM);
13310aa09f0SMatt Davis   FOS << '\n';
13410aa09f0SMatt Davis   FOS.flush();
13510aa09f0SMatt Davis 
136e02920feSWolfgang Pieb   ArrayRef<llvm::MCInst> Source = getSource();
13784d00513SAndrea Di Biagio   const unsigned Executions = LastInstructionIdx / Source.size() + 1;
13810aa09f0SMatt Davis   for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) {
13910aa09f0SMatt Davis     double Usage = ResourceUsage[I + Source.size() * E];
14010aa09f0SMatt Davis     printResourcePressure(FOS, Usage / Executions, (I + 1) * 7);
14110aa09f0SMatt Davis   }
14210aa09f0SMatt Davis 
14310aa09f0SMatt Davis   FOS.flush();
14410aa09f0SMatt Davis   OS << Buffer;
14510aa09f0SMatt Davis }
14610aa09f0SMatt Davis 
printResourcePressurePerInst(raw_ostream & OS) const14777c26aebSAndrea Di Biagio void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {
14810aa09f0SMatt Davis   std::string Buffer;
14910aa09f0SMatt Davis   raw_string_ostream TempStream(Buffer);
15010aa09f0SMatt Davis   formatted_raw_ostream FOS(TempStream);
15110aa09f0SMatt Davis 
15210aa09f0SMatt Davis   FOS << "\n\nResource pressure by instruction:\n";
153e02920feSWolfgang Pieb   printColumnNames(FOS, getSubTargetInfo().getSchedModel());
15410aa09f0SMatt Davis   FOS << "Instructions:\n";
15510aa09f0SMatt Davis 
1567be45b0fSAndrea Di Biagio   unsigned InstrIndex = 0;
157e02920feSWolfgang Pieb   ArrayRef<llvm::MCInst> Source = getSource();
15884d00513SAndrea Di Biagio   const unsigned Executions = LastInstructionIdx / Source.size() + 1;
1597be45b0fSAndrea Di Biagio   for (const MCInst &MCI : Source) {
1607be45b0fSAndrea Di Biagio     unsigned BaseEltIdx = InstrIndex * NumResourceUnits;
16110aa09f0SMatt Davis     for (unsigned J = 0; J < NumResourceUnits; ++J) {
1627be45b0fSAndrea Di Biagio       double Usage = ResourceUsage[J + BaseEltIdx];
16310aa09f0SMatt Davis       printResourcePressure(FOS, Usage / Executions, (J + 1) * 7);
16410aa09f0SMatt Davis     }
16510aa09f0SMatt Davis 
166e02920feSWolfgang Pieb     FOS << printInstructionString(MCI) << '\n';
16710aa09f0SMatt Davis     FOS.flush();
16810aa09f0SMatt Davis     OS << Buffer;
16910aa09f0SMatt Davis     Buffer = "";
1707be45b0fSAndrea Di Biagio 
1717be45b0fSAndrea Di Biagio     ++InstrIndex;
17210aa09f0SMatt Davis   }
17310aa09f0SMatt Davis }
174d38be2baSWolfgang Pieb 
toJSON() const175d38be2baSWolfgang Pieb json::Value ResourcePressureView::toJSON() const {
176d38be2baSWolfgang Pieb   // We're dumping the instructions and the ResourceUsage array.
177d38be2baSWolfgang Pieb   json::Array ResourcePressureInfo;
178d38be2baSWolfgang Pieb 
179d38be2baSWolfgang Pieb   // The ResourceUsage matrix is sparse, so we only consider
180d38be2baSWolfgang Pieb   // non-zero values.
181d38be2baSWolfgang Pieb   ArrayRef<llvm::MCInst> Source = getSource();
182d38be2baSWolfgang Pieb   const unsigned Executions = LastInstructionIdx / Source.size() + 1;
183d38be2baSWolfgang Pieb   for (const auto &R : enumerate(ResourceUsage)) {
184*85e3875aSMichael Maitland     const ReleaseAtCycles &RU = R.value();
185d38be2baSWolfgang Pieb     if (RU.getNumerator() == 0)
186d38be2baSWolfgang Pieb       continue;
187d38be2baSWolfgang Pieb     unsigned InstructionIndex = R.index() / NumResourceUnits;
188d38be2baSWolfgang Pieb     unsigned ResourceIndex = R.index() % NumResourceUnits;
189d38be2baSWolfgang Pieb     double Usage = RU / Executions;
190d38be2baSWolfgang Pieb     ResourcePressureInfo.push_back(
191d38be2baSWolfgang Pieb         json::Object({{"InstructionIndex", InstructionIndex},
192d38be2baSWolfgang Pieb                       {"ResourceIndex", ResourceIndex},
193d38be2baSWolfgang Pieb                       {"ResourceUsage", Usage}}));
194d38be2baSWolfgang Pieb   }
195d38be2baSWolfgang Pieb 
196d38be2baSWolfgang Pieb   json::Object JO({{"ResourcePressureInfo", std::move(ResourcePressureInfo)}});
197d38be2baSWolfgang Pieb   return JO;
198d38be2baSWolfgang Pieb }
19910aa09f0SMatt Davis } // namespace mca
2005a8fd657SFangrui Song } // namespace llvm
201