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 : 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(NumResourceUnits * (getSource().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 ArrayRef<llvm::MCInst> Source = getSource(); 56 const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size(); 57 for (const std::pair<ResourceRef, ResourceCycles> &Use : 58 IssueEvent.UsedResources) { 59 const ResourceRef &RR = Use.first; 60 assert(Resource2VecIndex.find(RR.first) != Resource2VecIndex.end()); 61 unsigned R2VIndex = Resource2VecIndex[RR.first]; 62 R2VIndex += countTrailingZeros(RR.second); 63 ResourceUsage[R2VIndex + NumResourceUnits * SourceIdx] += Use.second; 64 ResourceUsage[R2VIndex + NumResourceUnits * Source.size()] += Use.second; 65 } 66 } 67 68 static void printColumnNames(formatted_raw_ostream &OS, 69 const MCSchedModel &SM) { 70 unsigned Column = OS.getColumn(); 71 for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds(); 72 I < E; ++I) { 73 const MCProcResourceDesc &ProcResource = *SM.getProcResource(I); 74 unsigned NumUnits = ProcResource.NumUnits; 75 // Skip groups and invalid resources with zero units. 76 if (ProcResource.SubUnitsIdxBegin || !NumUnits) 77 continue; 78 79 for (unsigned J = 0; J < NumUnits; ++J) { 80 Column += 7; 81 OS << "[" << ResourceIndex; 82 if (NumUnits > 1) 83 OS << '.' << J; 84 OS << ']'; 85 OS.PadToColumn(Column); 86 } 87 88 ResourceIndex++; 89 } 90 } 91 92 static void printResourcePressure(formatted_raw_ostream &OS, double Pressure, 93 unsigned Col) { 94 if (!Pressure || Pressure < 0.005) { 95 OS << " - "; 96 } else { 97 // Round to the value to the nearest hundredth and then print it. 98 OS << format("%.2f", floor((Pressure * 100) + 0.5) / 100); 99 } 100 OS.PadToColumn(Col); 101 } 102 103 void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const { 104 std::string Buffer; 105 raw_string_ostream TempStream(Buffer); 106 formatted_raw_ostream FOS(TempStream); 107 108 FOS << "\n\nResources:\n"; 109 const MCSchedModel &SM = getSubTargetInfo().getSchedModel(); 110 for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds(); 111 I < E; ++I) { 112 const MCProcResourceDesc &ProcResource = *SM.getProcResource(I); 113 unsigned NumUnits = ProcResource.NumUnits; 114 // Skip groups and invalid resources with zero units. 115 if (ProcResource.SubUnitsIdxBegin || !NumUnits) 116 continue; 117 118 for (unsigned J = 0; J < NumUnits; ++J) { 119 FOS << '[' << ResourceIndex; 120 if (NumUnits > 1) 121 FOS << '.' << J; 122 FOS << ']'; 123 FOS.PadToColumn(6); 124 FOS << "- " << ProcResource.Name << '\n'; 125 } 126 127 ResourceIndex++; 128 } 129 130 FOS << "\n\nResource pressure per iteration:\n"; 131 FOS.flush(); 132 printColumnNames(FOS, SM); 133 FOS << '\n'; 134 FOS.flush(); 135 136 ArrayRef<llvm::MCInst> Source = getSource(); 137 const unsigned Executions = LastInstructionIdx / Source.size() + 1; 138 for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) { 139 double Usage = ResourceUsage[I + Source.size() * E]; 140 printResourcePressure(FOS, Usage / Executions, (I + 1) * 7); 141 } 142 143 FOS.flush(); 144 OS << Buffer; 145 } 146 147 void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const { 148 std::string Buffer; 149 raw_string_ostream TempStream(Buffer); 150 formatted_raw_ostream FOS(TempStream); 151 152 FOS << "\n\nResource pressure by instruction:\n"; 153 printColumnNames(FOS, getSubTargetInfo().getSchedModel()); 154 FOS << "Instructions:\n"; 155 156 unsigned InstrIndex = 0; 157 ArrayRef<llvm::MCInst> Source = getSource(); 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 FOS << printInstructionString(MCI) << '\n'; 167 FOS.flush(); 168 OS << Buffer; 169 Buffer = ""; 170 171 ++InstrIndex; 172 } 173 } 174 175 json::Value ResourcePressureView::toJSON() const { 176 // We're dumping the instructions and the ResourceUsage array. 177 json::Array ResourcePressureInfo; 178 179 // The ResourceUsage matrix is sparse, so we only consider 180 // non-zero values. 181 ArrayRef<llvm::MCInst> Source = getSource(); 182 const unsigned Executions = LastInstructionIdx / Source.size() + 1; 183 for (const auto &R : enumerate(ResourceUsage)) { 184 const ResourceCycles &RU = R.value(); 185 if (RU.getNumerator() == 0) 186 continue; 187 unsigned InstructionIndex = R.index() / NumResourceUnits; 188 unsigned ResourceIndex = R.index() % NumResourceUnits; 189 double Usage = RU / Executions; 190 ResourcePressureInfo.push_back( 191 json::Object({{"InstructionIndex", InstructionIndex}, 192 {"ResourceIndex", ResourceIndex}, 193 {"ResourceUsage", Usage}})); 194 } 195 196 json::Object JO({{"ResourcePressureInfo", std::move(ResourcePressureInfo)}}); 197 return JO; 198 } 199 } // namespace mca 200 } // namespace llvm 201