201 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--------------------- ResourcePressureView.cpp -------------*- C++ -*-===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
/// \file
 | 
						|
///
 | 
						|
/// This file implements methods in the ResourcePressureView interface.
 | 
						|
///
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "Views/ResourcePressureView.h"
 | 
						|
#include "llvm/Support/FormattedStream.h"
 | 
						|
#include "llvm/Support/raw_ostream.h"
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
namespace mca {
 | 
						|
 | 
						|
ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti,
 | 
						|
                                           MCInstPrinter &Printer,
 | 
						|
                                           ArrayRef<MCInst> S)
 | 
						|
    : InstructionView(sti, Printer, S), LastInstructionIdx(0) {
 | 
						|
  // Populate the map of resource descriptors.
 | 
						|
  unsigned R2VIndex = 0;
 | 
						|
  const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
 | 
						|
  for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
 | 
						|
    const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
 | 
						|
    unsigned NumUnits = ProcResource.NumUnits;
 | 
						|
    // Skip groups and invalid resources with zero units.
 | 
						|
    if (ProcResource.SubUnitsIdxBegin || !NumUnits)
 | 
						|
      continue;
 | 
						|
 | 
						|
    Resource2VecIndex.insert(std::pair<unsigned, unsigned>(I, R2VIndex));
 | 
						|
    R2VIndex += ProcResource.NumUnits;
 | 
						|
  }
 | 
						|
 | 
						|
  NumResourceUnits = R2VIndex;
 | 
						|
  ResourceUsage.resize(NumResourceUnits * (getSource().size() + 1));
 | 
						|
  std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0.0);
 | 
						|
}
 | 
						|
 | 
						|
void ResourcePressureView::onEvent(const HWInstructionEvent &Event) {
 | 
						|
  if (Event.Type == HWInstructionEvent::Dispatched) {
 | 
						|
    LastInstructionIdx = Event.IR.getSourceIndex();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // We're only interested in Issue events.
 | 
						|
  if (Event.Type != HWInstructionEvent::Issued)
 | 
						|
    return;
 | 
						|
 | 
						|
  const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event);
 | 
						|
  ArrayRef<llvm::MCInst> Source = getSource();
 | 
						|
  const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size();
 | 
						|
  for (const std::pair<ResourceRef, ResourceCycles> &Use :
 | 
						|
       IssueEvent.UsedResources) {
 | 
						|
    const ResourceRef &RR = Use.first;
 | 
						|
    assert(Resource2VecIndex.find(RR.first) != Resource2VecIndex.end());
 | 
						|
    unsigned R2VIndex = Resource2VecIndex[RR.first];
 | 
						|
    R2VIndex += countTrailingZeros(RR.second);
 | 
						|
    ResourceUsage[R2VIndex + NumResourceUnits * SourceIdx] += Use.second;
 | 
						|
    ResourceUsage[R2VIndex + NumResourceUnits * Source.size()] += Use.second;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void printColumnNames(formatted_raw_ostream &OS,
 | 
						|
                             const MCSchedModel &SM) {
 | 
						|
  unsigned Column = OS.getColumn();
 | 
						|
  for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
 | 
						|
       I < E; ++I) {
 | 
						|
    const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
 | 
						|
    unsigned NumUnits = ProcResource.NumUnits;
 | 
						|
    // Skip groups and invalid resources with zero units.
 | 
						|
    if (ProcResource.SubUnitsIdxBegin || !NumUnits)
 | 
						|
      continue;
 | 
						|
 | 
						|
    for (unsigned J = 0; J < NumUnits; ++J) {
 | 
						|
      Column += 7;
 | 
						|
      OS << "[" << ResourceIndex;
 | 
						|
      if (NumUnits > 1)
 | 
						|
        OS << '.' << J;
 | 
						|
      OS << ']';
 | 
						|
      OS.PadToColumn(Column);
 | 
						|
    }
 | 
						|
 | 
						|
    ResourceIndex++;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void printResourcePressure(formatted_raw_ostream &OS, double Pressure,
 | 
						|
                                  unsigned Col) {
 | 
						|
  if (!Pressure || Pressure < 0.005) {
 | 
						|
    OS << " - ";
 | 
						|
  } else {
 | 
						|
    // Round to the value to the nearest hundredth and then print it.
 | 
						|
    OS << format("%.2f", floor((Pressure * 100) + 0.5) / 100);
 | 
						|
  }
 | 
						|
  OS.PadToColumn(Col);
 | 
						|
}
 | 
						|
 | 
						|
void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const {
 | 
						|
  std::string Buffer;
 | 
						|
  raw_string_ostream TempStream(Buffer);
 | 
						|
  formatted_raw_ostream FOS(TempStream);
 | 
						|
 | 
						|
  FOS << "\n\nResources:\n";
 | 
						|
  const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
 | 
						|
  for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
 | 
						|
       I < E; ++I) {
 | 
						|
    const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
 | 
						|
    unsigned NumUnits = ProcResource.NumUnits;
 | 
						|
    // Skip groups and invalid resources with zero units.
 | 
						|
    if (ProcResource.SubUnitsIdxBegin || !NumUnits)
 | 
						|
      continue;
 | 
						|
 | 
						|
    for (unsigned J = 0; J < NumUnits; ++J) {
 | 
						|
      FOS << '[' << ResourceIndex;
 | 
						|
      if (NumUnits > 1)
 | 
						|
        FOS << '.' << J;
 | 
						|
      FOS << ']';
 | 
						|
      FOS.PadToColumn(6);
 | 
						|
      FOS << "- " << ProcResource.Name << '\n';
 | 
						|
    }
 | 
						|
 | 
						|
    ResourceIndex++;
 | 
						|
  }
 | 
						|
 | 
						|
  FOS << "\n\nResource pressure per iteration:\n";
 | 
						|
  FOS.flush();
 | 
						|
  printColumnNames(FOS, SM);
 | 
						|
  FOS << '\n';
 | 
						|
  FOS.flush();
 | 
						|
 | 
						|
  ArrayRef<llvm::MCInst> Source = getSource();
 | 
						|
  const unsigned Executions = LastInstructionIdx / Source.size() + 1;
 | 
						|
  for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) {
 | 
						|
    double Usage = ResourceUsage[I + Source.size() * E];
 | 
						|
    printResourcePressure(FOS, Usage / Executions, (I + 1) * 7);
 | 
						|
  }
 | 
						|
 | 
						|
  FOS.flush();
 | 
						|
  OS << Buffer;
 | 
						|
}
 | 
						|
 | 
						|
void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {
 | 
						|
  std::string Buffer;
 | 
						|
  raw_string_ostream TempStream(Buffer);
 | 
						|
  formatted_raw_ostream FOS(TempStream);
 | 
						|
 | 
						|
  FOS << "\n\nResource pressure by instruction:\n";
 | 
						|
  printColumnNames(FOS, getSubTargetInfo().getSchedModel());
 | 
						|
  FOS << "Instructions:\n";
 | 
						|
 | 
						|
  unsigned InstrIndex = 0;
 | 
						|
  ArrayRef<llvm::MCInst> Source = getSource();
 | 
						|
  const unsigned Executions = LastInstructionIdx / Source.size() + 1;
 | 
						|
  for (const MCInst &MCI : Source) {
 | 
						|
    unsigned BaseEltIdx = InstrIndex * NumResourceUnits;
 | 
						|
    for (unsigned J = 0; J < NumResourceUnits; ++J) {
 | 
						|
      double Usage = ResourceUsage[J + BaseEltIdx];
 | 
						|
      printResourcePressure(FOS, Usage / Executions, (J + 1) * 7);
 | 
						|
    }
 | 
						|
 | 
						|
    FOS << printInstructionString(MCI) << '\n';
 | 
						|
    FOS.flush();
 | 
						|
    OS << Buffer;
 | 
						|
    Buffer = "";
 | 
						|
 | 
						|
    ++InstrIndex;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
json::Value ResourcePressureView::toJSON() const {
 | 
						|
  // We're dumping the instructions and the ResourceUsage array.
 | 
						|
  json::Array ResourcePressureInfo;
 | 
						|
 | 
						|
  // The ResourceUsage matrix is sparse, so we only consider
 | 
						|
  // non-zero values.
 | 
						|
  ArrayRef<llvm::MCInst> Source = getSource();
 | 
						|
  const unsigned Executions = LastInstructionIdx / Source.size() + 1;
 | 
						|
  for (const auto &R : enumerate(ResourceUsage)) {
 | 
						|
    const ResourceCycles &RU = R.value();
 | 
						|
    if (RU.getNumerator() == 0)
 | 
						|
      continue;
 | 
						|
    unsigned InstructionIndex = R.index() / NumResourceUnits;
 | 
						|
    unsigned ResourceIndex = R.index() % NumResourceUnits;
 | 
						|
    double Usage = RU / Executions;
 | 
						|
    ResourcePressureInfo.push_back(
 | 
						|
        json::Object({{"InstructionIndex", InstructionIndex},
 | 
						|
                      {"ResourceIndex", ResourceIndex},
 | 
						|
                      {"ResourceUsage", Usage}}));
 | 
						|
  }
 | 
						|
 | 
						|
  json::Object JO({{"ResourcePressureInfo", std::move(ResourcePressureInfo)}});
 | 
						|
  return JO;
 | 
						|
}
 | 
						|
} // namespace mca
 | 
						|
} // namespace llvm
 |