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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// \file 9 /// 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 18 namespace llvm { 19 namespace mca { 20 21 ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti, 22 MCInstPrinter &Printer, 23 ArrayRef<MCInst> S) 24 : STI(sti), MCIP(Printer), Source(S), LastInstructionIdx(0) { 25 // Populate the map of resource descriptors. 26 unsigned R2VIndex = 0; 27 const MCSchedModel &SM = STI.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(NumResourceUnits * (Source.size() + 1)); 41 std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0.0); 42 } 43 44 void ResourcePressureView::onEvent(const HWInstructionEvent &Event) { 45 if (Event.Type == HWInstructionEvent::Dispatched) { 46 LastInstructionIdx = Event.IR.getSourceIndex(); 47 return; 48 } 49 50 // We're only interested in Issue events. 51 if (Event.Type != HWInstructionEvent::Issued) 52 return; 53 54 const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event); 55 const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size(); 56 for (const std::pair<ResourceRef, ResourceCycles> &Use : 57 IssueEvent.UsedResources) { 58 const ResourceRef &RR = Use.first; 59 assert(Resource2VecIndex.find(RR.first) != Resource2VecIndex.end()); 60 unsigned R2VIndex = Resource2VecIndex[RR.first]; 61 R2VIndex += countTrailingZeros(RR.second); 62 ResourceUsage[R2VIndex + NumResourceUnits * SourceIdx] += Use.second; 63 ResourceUsage[R2VIndex + NumResourceUnits * Source.size()] += Use.second; 64 } 65 } 66 67 static void printColumnNames(formatted_raw_ostream &OS, 68 const MCSchedModel &SM) { 69 unsigned Column = OS.getColumn(); 70 for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds(); 71 I < E; ++I) { 72 const MCProcResourceDesc &ProcResource = *SM.getProcResource(I); 73 unsigned NumUnits = ProcResource.NumUnits; 74 // Skip groups and invalid resources with zero units. 75 if (ProcResource.SubUnitsIdxBegin || !NumUnits) 76 continue; 77 78 for (unsigned J = 0; J < NumUnits; ++J) { 79 Column += 7; 80 OS << "[" << ResourceIndex; 81 if (NumUnits > 1) 82 OS << '.' << J; 83 OS << ']'; 84 OS.PadToColumn(Column); 85 } 86 87 ResourceIndex++; 88 } 89 } 90 91 static void printResourcePressure(formatted_raw_ostream &OS, double Pressure, 92 unsigned Col) { 93 if (!Pressure || Pressure < 0.005) { 94 OS << " - "; 95 } else { 96 // Round to the value to the nearest hundredth and then print it. 97 OS << format("%.2f", floor((Pressure * 100) + 0.5) / 100); 98 } 99 OS.PadToColumn(Col); 100 } 101 102 void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const { 103 std::string Buffer; 104 raw_string_ostream TempStream(Buffer); 105 formatted_raw_ostream FOS(TempStream); 106 107 FOS << "\n\nResources:\n"; 108 const MCSchedModel &SM = STI.getSchedModel(); 109 for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds(); 110 I < E; ++I) { 111 const MCProcResourceDesc &ProcResource = *SM.getProcResource(I); 112 unsigned NumUnits = ProcResource.NumUnits; 113 // Skip groups and invalid resources with zero units. 114 if (ProcResource.SubUnitsIdxBegin || !NumUnits) 115 continue; 116 117 for (unsigned J = 0; J < NumUnits; ++J) { 118 FOS << '[' << ResourceIndex; 119 if (NumUnits > 1) 120 FOS << '.' << J; 121 FOS << ']'; 122 FOS.PadToColumn(6); 123 FOS << "- " << ProcResource.Name << '\n'; 124 } 125 126 ResourceIndex++; 127 } 128 129 FOS << "\n\nResource pressure per iteration:\n"; 130 FOS.flush(); 131 printColumnNames(FOS, SM); 132 FOS << '\n'; 133 FOS.flush(); 134 135 const unsigned Executions = LastInstructionIdx / Source.size() + 1; 136 for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) { 137 double Usage = ResourceUsage[I + Source.size() * E]; 138 printResourcePressure(FOS, Usage / Executions, (I + 1) * 7); 139 } 140 141 FOS.flush(); 142 OS << Buffer; 143 } 144 145 void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const { 146 std::string Buffer; 147 raw_string_ostream TempStream(Buffer); 148 formatted_raw_ostream FOS(TempStream); 149 150 FOS << "\n\nResource pressure by instruction:\n"; 151 printColumnNames(FOS, STI.getSchedModel()); 152 FOS << "Instructions:\n"; 153 154 std::string Instruction; 155 raw_string_ostream InstrStream(Instruction); 156 157 unsigned InstrIndex = 0; 158 const unsigned Executions = LastInstructionIdx / Source.size() + 1; 159 for (const MCInst &MCI : Source) { 160 unsigned BaseEltIdx = InstrIndex * NumResourceUnits; 161 for (unsigned J = 0; J < NumResourceUnits; ++J) { 162 double Usage = ResourceUsage[J + BaseEltIdx]; 163 printResourcePressure(FOS, Usage / Executions, (J + 1) * 7); 164 } 165 166 MCIP.printInst(&MCI, 0, "", STI, InstrStream); 167 InstrStream.flush(); 168 StringRef Str(Instruction); 169 170 // Remove any tabs or spaces at the beginning of the instruction. 171 Str = Str.ltrim(); 172 173 FOS << Str << '\n'; 174 Instruction = ""; 175 176 FOS.flush(); 177 OS << Buffer; 178 Buffer = ""; 179 180 ++InstrIndex; 181 } 182 } 183 } // namespace mca 184 } // namespace llvm 185