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