| //===--------------------- ResourcePressureView.cpp -------------*- C++ -*-===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// \file | |
| /// | |
| /// This file implements methods in the ResourcePressureView interface. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "ResourcePressureView.h" | |
| #include "llvm/Support/FormattedStream.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| namespace mca { | |
| using namespace llvm; | |
| void ResourcePressureView::initialize() { | |
| // Populate the map of resource descriptors. | |
| unsigned R2VIndex = 0; | |
| const MCSchedModel &SM = STI.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 * (Source.size() + 1)); | |
| std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0.0); | |
| } | |
| void ResourcePressureView::onEvent(const HWInstructionEvent &Event) { | |
| // We're only interested in Issue events. | |
| if (Event.Type != HWInstructionEvent::Issued) | |
| return; | |
| const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event); | |
| const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size(); | |
| for (const std::pair<ResourceRef, double> &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::printResourcePressurePerIteration( | |
| raw_ostream &OS, unsigned Executions) const { | |
| std::string Buffer; | |
| raw_string_ostream TempStream(Buffer); | |
| formatted_raw_ostream FOS(TempStream); | |
| FOS << "\n\nResources:\n"; | |
| const MCSchedModel &SM = STI.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(); | |
| 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::printResourcePressurePerInstruction( | |
| raw_ostream &OS, unsigned Executions) const { | |
| std::string Buffer; | |
| raw_string_ostream TempStream(Buffer); | |
| formatted_raw_ostream FOS(TempStream); | |
| FOS << "\n\nResource pressure by instruction:\n"; | |
| printColumnNames(FOS, STI.getSchedModel()); | |
| FOS << "Instructions:\n"; | |
| std::string Instruction; | |
| raw_string_ostream InstrStream(Instruction); | |
| for (unsigned I = 0, E = Source.size(); I < E; ++I) { | |
| for (unsigned J = 0; J < NumResourceUnits; ++J) { | |
| double Usage = ResourceUsage[J + I * NumResourceUnits]; | |
| printResourcePressure(FOS, Usage / Executions, (J + 1) * 7); | |
| } | |
| MCIP.printInst(&Source.getMCInstFromIndex(I), InstrStream, "", STI); | |
| InstrStream.flush(); | |
| StringRef Str(Instruction); | |
| // Remove any tabs or spaces at the beginning of the instruction. | |
| Str = Str.ltrim(); | |
| FOS << Str << '\n'; | |
| Instruction = ""; | |
| FOS.flush(); | |
| OS << Buffer; | |
| Buffer = ""; | |
| } | |
| } | |
| } // namespace mca |