1 //===--------------------- SchedulerStatistics.cpp --------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// \file 10 /// 11 /// This file implements the SchedulerStatistics interface. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "Views/SchedulerStatistics.h" 16 #include "llvm/Support/Format.h" 17 #include "llvm/Support/FormattedStream.h" 18 19 namespace llvm { 20 namespace mca { 21 22 SchedulerStatistics::SchedulerStatistics(const llvm::MCSubtargetInfo &STI) 23 : SM(STI.getSchedModel()), LQResourceID(0), SQResourceID(0), NumIssued(0), 24 NumCycles(0), MostRecentLoadDispatched(~0U), 25 MostRecentStoreDispatched(~0U), 26 IssuedPerCycle(STI.getSchedModel().NumProcResourceKinds, 0), 27 Usage(STI.getSchedModel().NumProcResourceKinds, {0, 0, 0}) { 28 if (SM.hasExtraProcessorInfo()) { 29 const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo(); 30 LQResourceID = EPI.LoadQueueID; 31 SQResourceID = EPI.StoreQueueID; 32 } 33 } 34 35 // FIXME: This implementation works under the assumption that load/store queue 36 // entries are reserved at 'instruction dispatched' stage, and released at 37 // 'instruction executed' stage. This currently matches the behavior of LSUnit. 38 // 39 // The current design minimizes the number of events generated by the 40 // Dispatch/Execute stages, at the cost of doing extra bookkeeping in method 41 // `onEvent`. However, it introduces a subtle dependency between this view and 42 // how the LSUnit works. 43 // 44 // In future we should add a new "memory queue" event type, so that we stop 45 // making assumptions on how LSUnit internally works (See PR39828). 46 void SchedulerStatistics::onEvent(const HWInstructionEvent &Event) { 47 if (Event.Type == HWInstructionEvent::Issued) 48 ++NumIssued; 49 else if (Event.Type == HWInstructionEvent::Dispatched) { 50 const Instruction &Inst = *Event.IR.getInstruction(); 51 const unsigned Index = Event.IR.getSourceIndex(); 52 if (LQResourceID && Inst.getDesc().MayLoad && 53 MostRecentLoadDispatched != Index) { 54 Usage[LQResourceID].SlotsInUse++; 55 MostRecentLoadDispatched = Index; 56 } 57 if (SQResourceID && Inst.getDesc().MayStore && 58 MostRecentStoreDispatched != Index) { 59 Usage[SQResourceID].SlotsInUse++; 60 MostRecentStoreDispatched = Index; 61 } 62 } else if (Event.Type == HWInstructionEvent::Executed) { 63 const Instruction &Inst = *Event.IR.getInstruction(); 64 if (LQResourceID && Inst.getDesc().MayLoad) { 65 assert(Usage[LQResourceID].SlotsInUse); 66 Usage[LQResourceID].SlotsInUse--; 67 } 68 if (SQResourceID && Inst.getDesc().MayStore) { 69 assert(Usage[SQResourceID].SlotsInUse); 70 Usage[SQResourceID].SlotsInUse--; 71 } 72 } 73 } 74 75 void SchedulerStatistics::onReservedBuffers(const InstRef & /* unused */, 76 ArrayRef<unsigned> Buffers) { 77 for (const unsigned Buffer : Buffers) { 78 if (Buffer == LQResourceID || Buffer == SQResourceID) 79 continue; 80 Usage[Buffer].SlotsInUse++; 81 } 82 } 83 84 void SchedulerStatistics::onReleasedBuffers(const InstRef & /* unused */, 85 ArrayRef<unsigned> Buffers) { 86 for (const unsigned Buffer : Buffers) { 87 if (Buffer == LQResourceID || Buffer == SQResourceID) 88 continue; 89 Usage[Buffer].SlotsInUse--; 90 } 91 } 92 93 void SchedulerStatistics::updateHistograms() { 94 for (BufferUsage &BU : Usage) { 95 BU.CumulativeNumUsedSlots += BU.SlotsInUse; 96 BU.MaxUsedSlots = std::max(BU.MaxUsedSlots, BU.SlotsInUse); 97 } 98 99 IssuedPerCycle[NumIssued]++; 100 NumIssued = 0; 101 } 102 103 void SchedulerStatistics::printSchedulerStats(raw_ostream &OS) const { 104 OS << "\n\nSchedulers - " 105 << "number of cycles where we saw N instructions issued:\n"; 106 OS << "[# issued], [# cycles]\n"; 107 108 const auto It = 109 std::max_element(IssuedPerCycle.begin(), IssuedPerCycle.end()); 110 unsigned Index = std::distance(IssuedPerCycle.begin(), It); 111 112 bool HasColors = OS.has_colors(); 113 for (unsigned I = 0, E = IssuedPerCycle.size(); I < E; ++I) { 114 unsigned IPC = IssuedPerCycle[I]; 115 if (!IPC) 116 continue; 117 118 if (I == Index && HasColors) 119 OS.changeColor(raw_ostream::SAVEDCOLOR, true, false); 120 121 OS << " " << I << ", " << IPC << " (" 122 << format("%.1f", ((double)IPC / NumCycles) * 100) << "%)\n"; 123 if (HasColors) 124 OS.resetColor(); 125 } 126 } 127 128 void SchedulerStatistics::printSchedulerUsage(raw_ostream &OS) const { 129 assert(NumCycles && "Unexpected number of cycles!"); 130 131 OS << "\nScheduler's queue usage:\n"; 132 if (all_of(Usage, [](const BufferUsage &BU) { return !BU.MaxUsedSlots; })) { 133 OS << "No scheduler resources used.\n"; 134 return; 135 } 136 137 OS << "[1] Resource name.\n" 138 << "[2] Average number of used buffer entries.\n" 139 << "[3] Maximum number of used buffer entries.\n" 140 << "[4] Total number of buffer entries.\n\n" 141 << " [1] [2] [3] [4]\n"; 142 143 formatted_raw_ostream FOS(OS); 144 bool HasColors = FOS.has_colors(); 145 for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) { 146 const MCProcResourceDesc &ProcResource = *SM.getProcResource(I); 147 if (ProcResource.BufferSize <= 0) 148 continue; 149 150 const BufferUsage &BU = Usage[I]; 151 double AvgUsage = (double)BU.CumulativeNumUsedSlots / NumCycles; 152 double AlmostFullThreshold = (double)(ProcResource.BufferSize * 4) / 5; 153 unsigned NormalizedAvg = floor((AvgUsage * 10) + 0.5) / 10; 154 unsigned NormalizedThreshold = floor((AlmostFullThreshold * 10) + 0.5) / 10; 155 156 FOS << ProcResource.Name; 157 FOS.PadToColumn(17); 158 if (HasColors && NormalizedAvg >= NormalizedThreshold) 159 FOS.changeColor(raw_ostream::YELLOW, true, false); 160 FOS << NormalizedAvg; 161 if (HasColors) 162 FOS.resetColor(); 163 FOS.PadToColumn(28); 164 if (HasColors && 165 BU.MaxUsedSlots == static_cast<unsigned>(ProcResource.BufferSize)) 166 FOS.changeColor(raw_ostream::RED, true, false); 167 FOS << BU.MaxUsedSlots; 168 if (HasColors) 169 FOS.resetColor(); 170 FOS.PadToColumn(39); 171 FOS << ProcResource.BufferSize << '\n'; 172 } 173 174 FOS.flush(); 175 } 176 177 void SchedulerStatistics::printView(raw_ostream &OS) const { 178 printSchedulerStats(OS); 179 printSchedulerUsage(OS); 180 } 181 182 } // namespace mca 183 } // namespace llvm 184