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