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
|