brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.9 KiB · 556c911 Raw
238 lines · cpp
1//===--------------------- ResourcePressureView.cpp -------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8/// \file9///10/// This file implements methods in the ResourcePressureView interface.11///12//===----------------------------------------------------------------------===//13 14#include "Views/ResourcePressureView.h"15#include "llvm/Support/FormattedStream.h"16#include "llvm/Support/raw_ostream.h"17 18namespace llvm {19namespace mca {20 21ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti,22                                           MCInstPrinter &Printer,23                                           ArrayRef<MCInst> S)24    : InstructionView(sti, Printer, S), LastInstructionIdx(0) {25  // Populate the map of resource descriptors.26  unsigned R2VIndex = 0;27  const MCSchedModel &SM = getSubTargetInfo().getSchedModel();28  for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {29    const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);30    unsigned NumUnits = ProcResource.NumUnits;31    // Skip groups and invalid resources with zero units.32    if (ProcResource.SubUnitsIdxBegin || !NumUnits)33      continue;34 35    Resource2VecIndex.insert(std::pair<unsigned, unsigned>(I, R2VIndex));36    R2VIndex += ProcResource.NumUnits;37  }38 39  NumResourceUnits = R2VIndex;40  ResourceUsage.resize(getSource().size());41 42  ResourceReleaseAtCycles InitValue{0, 0};43  auto Generator = [&InitValue]() {44    ResourceReleaseAtCycles Old = InitValue;45    ++InitValue.ResourceIdx;46    return Old;47  };48  std::generate_n(std::back_inserter(CommonResourceUsage), NumResourceUnits,49                  Generator);50}51 52void ResourcePressureView::onEvent(const HWInstructionEvent &Event) {53  if (Event.Type == HWInstructionEvent::Dispatched) {54    LastInstructionIdx = Event.IR.getSourceIndex();55    return;56  }57 58  // We're only interested in Issue events.59  if (Event.Type != HWInstructionEvent::Issued)60    return;61 62  const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event);63  ArrayRef<llvm::MCInst> Source = getSource();64  const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size();65  for (const std::pair<ResourceRef, ReleaseAtCycles> &Use :66       IssueEvent.UsedResources) {67    const ResourceRef &RR = Use.first;68    assert(Resource2VecIndex.contains(RR.first));69    unsigned R2VIndex = Resource2VecIndex[RR.first];70    R2VIndex += llvm::countr_zero(RR.second);71 72    InstResourceUsage &RU = ResourceUsage[SourceIdx];73    ResourceReleaseAtCycles NewUsage{R2VIndex, Use.second};74    auto ResCyclesIt =75        lower_bound(RU, NewUsage, [](const auto &L, const auto &R) {76          return L.ResourceIdx < R.ResourceIdx;77        });78    if (ResCyclesIt != RU.end() && ResCyclesIt->ResourceIdx == R2VIndex)79      ResCyclesIt->Cycles += NewUsage.Cycles;80    else81      RU.insert(ResCyclesIt, std::move(NewUsage));82 83    CommonResourceUsage[R2VIndex].Cycles += NewUsage.Cycles;84  }85}86 87static void printColumnNames(formatted_raw_ostream &OS,88                             const MCSchedModel &SM) {89  unsigned Column = OS.getColumn();90  for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();91       I < E; ++I) {92    const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);93    unsigned NumUnits = ProcResource.NumUnits;94    // Skip groups and invalid resources with zero units.95    if (ProcResource.SubUnitsIdxBegin || !NumUnits)96      continue;97 98    for (unsigned J = 0; J < NumUnits; ++J) {99      Column += 7;100      OS << "[" << ResourceIndex;101      if (NumUnits > 1)102        OS << '.' << J;103      OS << ']';104      OS.PadToColumn(Column);105    }106 107    ResourceIndex++;108  }109}110 111static void printResourcePressure(formatted_raw_ostream &OS, double Pressure,112                                  unsigned Col) {113  if (!Pressure || Pressure < 0.005) {114    OS << " - ";115  } else {116    // Round to the value to the nearest hundredth and then print it.117    OS << format("%.2f", floor((Pressure * 100) + 0.5) / 100);118  }119  OS.PadToColumn(Col);120}121 122void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const {123  std::string Buffer;124  raw_string_ostream TempStream(Buffer);125  formatted_raw_ostream FOS(TempStream);126 127  FOS << "\n\nResources:\n";128  const MCSchedModel &SM = getSubTargetInfo().getSchedModel();129  for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();130       I < E; ++I) {131    const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);132    unsigned NumUnits = ProcResource.NumUnits;133    // Skip groups and invalid resources with zero units.134    if (ProcResource.SubUnitsIdxBegin || !NumUnits)135      continue;136 137    for (unsigned J = 0; J < NumUnits; ++J) {138      FOS << '[' << ResourceIndex;139      if (NumUnits > 1)140        FOS << '.' << J;141      FOS << ']';142      FOS.PadToColumn(6);143      FOS << "- " << ProcResource.Name << '\n';144    }145 146    ResourceIndex++;147  }148 149  FOS << "\n\nResource pressure per iteration:\n";150  FOS.flush();151  printColumnNames(FOS, SM);152  FOS << '\n';153  FOS.flush();154 155  ArrayRef<llvm::MCInst> Source = getSource();156  const unsigned Executions = LastInstructionIdx / Source.size() + 1;157  auto UsageEntryEnd = CommonResourceUsage.end();158  auto UsageEntryIt = CommonResourceUsage.begin();159  for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) {160    double Pressure = 0.0;161    if (UsageEntryIt != UsageEntryEnd && UsageEntryIt->ResourceIdx == I) {162      Pressure = UsageEntryIt->Cycles / Executions;163      ++UsageEntryIt;164    }165    printResourcePressure(FOS, Pressure, (I + 1) * 7);166  }167  assert(UsageEntryIt == UsageEntryEnd);168 169  FOS.flush();170  OS << Buffer;171}172 173void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {174  std::string Buffer;175  raw_string_ostream TempStream(Buffer);176  formatted_raw_ostream FOS(TempStream);177 178  FOS << "\n\nResource pressure by instruction:\n";179  printColumnNames(FOS, getSubTargetInfo().getSchedModel());180  FOS << "Instructions:\n";181 182  unsigned InstrIndex = 0;183  ArrayRef<llvm::MCInst> Source = getSource();184  const unsigned Executions = LastInstructionIdx / Source.size() + 1;185  for (const MCInst &MCI : Source) {186    auto UsageEntryEnd = ResourceUsage[InstrIndex].end();187    auto UsageEntryIt = ResourceUsage[InstrIndex].begin();188    for (unsigned J = 0; J < NumResourceUnits; ++J) {189      double Pressure = 0.0;190      if (UsageEntryIt != UsageEntryEnd && UsageEntryIt->ResourceIdx == J) {191        Pressure = UsageEntryIt->Cycles / Executions;192        ++UsageEntryIt;193      }194      printResourcePressure(FOS, Pressure, (J + 1) * 7);195    }196    assert(UsageEntryIt == UsageEntryEnd);197 198    FOS << printInstructionString(MCI) << '\n';199    FOS.flush();200    OS << Buffer;201    Buffer = "";202 203    ++InstrIndex;204  }205}206 207json::Value ResourcePressureView::toJSON() const {208  // We're dumping the instructions and the ResourceUsage array.209  json::Array ResourcePressureInfo;210 211  // The ResourceUsage matrix is sparse, so we only consider212  // non-zero values.213  ArrayRef<llvm::MCInst> Source = getSource();214  const unsigned Executions = LastInstructionIdx / Source.size() + 1;215 216  auto AddToJSON = [&ResourcePressureInfo, Executions](217                       const ResourceReleaseAtCycles &RU, unsigned InstIndex) {218    assert(RU.Cycles.getNumerator() != 0);219    double Usage = RU.Cycles / Executions;220    ResourcePressureInfo.push_back(221        json::Object({{"InstructionIndex", InstIndex},222                      {"ResourceIndex", RU.ResourceIdx},223                      {"ResourceUsage", Usage}}));224  };225  for (const auto &[InstIndex, Usages] : enumerate(ResourceUsage))226    for (const auto &RU : Usages)227      AddToJSON(RU, InstIndex);228  for (const auto &RU : CommonResourceUsage) {229    if (RU.Cycles.getNumerator() != 0)230      AddToJSON(RU, Source.size());231  }232 233  json::Object JO({{"ResourcePressureInfo", std::move(ResourcePressureInfo)}});234  return JO;235}236} // namespace mca237} // namespace llvm238