Path: blob/main/contrib/llvm-project/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp
35290 views
//===--------------------- ResourcePressureView.cpp -------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7/// \file8///9/// This file implements methods in the ResourcePressureView interface.10///11//===----------------------------------------------------------------------===//1213#include "Views/ResourcePressureView.h"14#include "llvm/Support/FormattedStream.h"15#include "llvm/Support/raw_ostream.h"1617namespace llvm {18namespace mca {1920ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti,21MCInstPrinter &Printer,22ArrayRef<MCInst> S)23: InstructionView(sti, Printer, S), LastInstructionIdx(0) {24// Populate the map of resource descriptors.25unsigned R2VIndex = 0;26const MCSchedModel &SM = getSubTargetInfo().getSchedModel();27for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {28const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);29unsigned NumUnits = ProcResource.NumUnits;30// Skip groups and invalid resources with zero units.31if (ProcResource.SubUnitsIdxBegin || !NumUnits)32continue;3334Resource2VecIndex.insert(std::pair<unsigned, unsigned>(I, R2VIndex));35R2VIndex += ProcResource.NumUnits;36}3738NumResourceUnits = R2VIndex;39ResourceUsage.resize(NumResourceUnits * (getSource().size() + 1));40std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0.0);41}4243void ResourcePressureView::onEvent(const HWInstructionEvent &Event) {44if (Event.Type == HWInstructionEvent::Dispatched) {45LastInstructionIdx = Event.IR.getSourceIndex();46return;47}4849// We're only interested in Issue events.50if (Event.Type != HWInstructionEvent::Issued)51return;5253const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event);54ArrayRef<llvm::MCInst> Source = getSource();55const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size();56for (const std::pair<ResourceRef, ReleaseAtCycles> &Use :57IssueEvent.UsedResources) {58const ResourceRef &RR = Use.first;59assert(Resource2VecIndex.contains(RR.first));60unsigned R2VIndex = Resource2VecIndex[RR.first];61R2VIndex += llvm::countr_zero(RR.second);62ResourceUsage[R2VIndex + NumResourceUnits * SourceIdx] += Use.second;63ResourceUsage[R2VIndex + NumResourceUnits * Source.size()] += Use.second;64}65}6667static void printColumnNames(formatted_raw_ostream &OS,68const MCSchedModel &SM) {69unsigned Column = OS.getColumn();70for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();71I < E; ++I) {72const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);73unsigned NumUnits = ProcResource.NumUnits;74// Skip groups and invalid resources with zero units.75if (ProcResource.SubUnitsIdxBegin || !NumUnits)76continue;7778for (unsigned J = 0; J < NumUnits; ++J) {79Column += 7;80OS << "[" << ResourceIndex;81if (NumUnits > 1)82OS << '.' << J;83OS << ']';84OS.PadToColumn(Column);85}8687ResourceIndex++;88}89}9091static void printResourcePressure(formatted_raw_ostream &OS, double Pressure,92unsigned Col) {93if (!Pressure || Pressure < 0.005) {94OS << " - ";95} else {96// Round to the value to the nearest hundredth and then print it.97OS << format("%.2f", floor((Pressure * 100) + 0.5) / 100);98}99OS.PadToColumn(Col);100}101102void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const {103std::string Buffer;104raw_string_ostream TempStream(Buffer);105formatted_raw_ostream FOS(TempStream);106107FOS << "\n\nResources:\n";108const MCSchedModel &SM = getSubTargetInfo().getSchedModel();109for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();110I < E; ++I) {111const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);112unsigned NumUnits = ProcResource.NumUnits;113// Skip groups and invalid resources with zero units.114if (ProcResource.SubUnitsIdxBegin || !NumUnits)115continue;116117for (unsigned J = 0; J < NumUnits; ++J) {118FOS << '[' << ResourceIndex;119if (NumUnits > 1)120FOS << '.' << J;121FOS << ']';122FOS.PadToColumn(6);123FOS << "- " << ProcResource.Name << '\n';124}125126ResourceIndex++;127}128129FOS << "\n\nResource pressure per iteration:\n";130FOS.flush();131printColumnNames(FOS, SM);132FOS << '\n';133FOS.flush();134135ArrayRef<llvm::MCInst> Source = getSource();136const unsigned Executions = LastInstructionIdx / Source.size() + 1;137for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) {138double Usage = ResourceUsage[I + Source.size() * E];139printResourcePressure(FOS, Usage / Executions, (I + 1) * 7);140}141142FOS.flush();143OS << Buffer;144}145146void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {147std::string Buffer;148raw_string_ostream TempStream(Buffer);149formatted_raw_ostream FOS(TempStream);150151FOS << "\n\nResource pressure by instruction:\n";152printColumnNames(FOS, getSubTargetInfo().getSchedModel());153FOS << "Instructions:\n";154155unsigned InstrIndex = 0;156ArrayRef<llvm::MCInst> Source = getSource();157const unsigned Executions = LastInstructionIdx / Source.size() + 1;158for (const MCInst &MCI : Source) {159unsigned BaseEltIdx = InstrIndex * NumResourceUnits;160for (unsigned J = 0; J < NumResourceUnits; ++J) {161double Usage = ResourceUsage[J + BaseEltIdx];162printResourcePressure(FOS, Usage / Executions, (J + 1) * 7);163}164165FOS << printInstructionString(MCI) << '\n';166FOS.flush();167OS << Buffer;168Buffer = "";169170++InstrIndex;171}172}173174json::Value ResourcePressureView::toJSON() const {175// We're dumping the instructions and the ResourceUsage array.176json::Array ResourcePressureInfo;177178// The ResourceUsage matrix is sparse, so we only consider179// non-zero values.180ArrayRef<llvm::MCInst> Source = getSource();181const unsigned Executions = LastInstructionIdx / Source.size() + 1;182for (const auto &R : enumerate(ResourceUsage)) {183const ReleaseAtCycles &RU = R.value();184if (RU.getNumerator() == 0)185continue;186unsigned InstructionIndex = R.index() / NumResourceUnits;187unsigned ResourceIndex = R.index() % NumResourceUnits;188double Usage = RU / Executions;189ResourcePressureInfo.push_back(190json::Object({{"InstructionIndex", InstructionIndex},191{"ResourceIndex", ResourceIndex},192{"ResourceUsage", Usage}}));193}194195json::Object JO({{"ResourcePressureInfo", std::move(ResourcePressureInfo)}});196return JO;197}198} // namespace mca199} // namespace llvm200201202