Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame^] | 1 | //===--------------------- BackendPrinter.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 BackendPrinter interface. |
| 12 | /// |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "BackendPrinter.h" |
| 16 | #include "llvm/CodeGen/TargetSchedule.h" |
| 17 | |
| 18 | namespace mca { |
| 19 | |
| 20 | using namespace llvm; |
| 21 | |
| 22 | std::unique_ptr<ToolOutputFile> |
| 23 | BackendPrinter::getOutputStream(std::string OutputFile) { |
| 24 | if (OutputFile == "") |
| 25 | OutputFile = "-"; |
| 26 | std::error_code EC; |
| 27 | auto Out = llvm::make_unique<ToolOutputFile>(OutputFile, EC, sys::fs::F_None); |
| 28 | if (!EC) |
| 29 | return Out; |
| 30 | errs() << EC.message() << '\n'; |
| 31 | return nullptr; |
| 32 | } |
| 33 | |
| 34 | void BackendPrinter::printGeneralStatistics(unsigned Iterations, |
| 35 | unsigned Cycles, |
| 36 | unsigned Instructions, |
| 37 | unsigned DispatchWidth) const { |
| 38 | unsigned TotalInstructions = Instructions * Iterations; |
| 39 | double IPC = (double)TotalInstructions / Cycles; |
| 40 | |
| 41 | std::string Buffer; |
| 42 | raw_string_ostream TempStream(Buffer); |
| 43 | TempStream << "Iterations: " << Iterations; |
| 44 | TempStream << "\nInstructions: " << TotalInstructions; |
| 45 | TempStream << "\nTotal Cycles: " << Cycles; |
| 46 | TempStream << "\nDispatch Width: " << DispatchWidth; |
| 47 | TempStream << "\nIPC: " << format("%.2f", IPC) << '\n'; |
| 48 | TempStream.flush(); |
| 49 | File->os() << Buffer; |
| 50 | } |
| 51 | |
| 52 | void BackendPrinter::printRATStatistics(unsigned TotalMappings, |
| 53 | unsigned MaxUsedMappings) const { |
| 54 | std::string Buffer; |
| 55 | raw_string_ostream TempStream(Buffer); |
| 56 | TempStream << "\n\nRegister Alias Table:"; |
| 57 | TempStream << "\nTotal number of mappings created: " << TotalMappings; |
| 58 | TempStream << "\nMax number of mappings used: " << MaxUsedMappings |
| 59 | << '\n'; |
| 60 | TempStream.flush(); |
| 61 | File->os() << Buffer; |
| 62 | } |
| 63 | |
| 64 | void BackendPrinter::printDispatchStalls(unsigned RATStalls, unsigned RCUStalls, |
| 65 | unsigned SCHEDQStalls, |
| 66 | unsigned LDQStalls, unsigned STQStalls, |
| 67 | unsigned DGStalls) const { |
| 68 | std::string Buffer; |
| 69 | raw_string_ostream TempStream(Buffer); |
| 70 | TempStream << "\n\nDynamic Dispatch Stall Cycles:\n"; |
| 71 | TempStream << "RAT - Register unavailable: " |
| 72 | << RATStalls; |
| 73 | TempStream << "\nRCU - Retire tokens unavailable: " |
| 74 | << RCUStalls; |
| 75 | TempStream << "\nSCHEDQ - Scheduler full: " |
| 76 | << SCHEDQStalls; |
| 77 | TempStream << "\nLQ - Load queue full: " |
| 78 | << LDQStalls; |
| 79 | TempStream << "\nSQ - Store queue full: " |
| 80 | << STQStalls; |
| 81 | TempStream << "\nGROUP - Static restrictions on the dispatch group: " |
| 82 | << DGStalls; |
| 83 | TempStream << '\n'; |
| 84 | TempStream.flush(); |
| 85 | File->os() << Buffer; |
| 86 | } |
| 87 | |
| 88 | void BackendPrinter::printSchedulerUsage( |
| 89 | const MCSchedModel &SM, const ArrayRef<BufferUsageEntry> &Usage) const { |
| 90 | std::string Buffer; |
| 91 | raw_string_ostream TempStream(Buffer); |
| 92 | TempStream << "\n\nScheduler's queue usage:\n"; |
| 93 | const ArrayRef<uint64_t> ResourceMasks = B.getProcResourceMasks(); |
| 94 | for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) { |
| 95 | const MCProcResourceDesc &ProcResource = *SM.getProcResource(I); |
| 96 | if (!ProcResource.BufferSize) |
| 97 | continue; |
| 98 | |
| 99 | for (const BufferUsageEntry &Entry : Usage) |
| 100 | if (ResourceMasks[I] == Entry.first) |
| 101 | TempStream << ProcResource.Name << ", " << Entry.second << '/' |
| 102 | << ProcResource.BufferSize << '\n'; |
| 103 | } |
| 104 | |
| 105 | TempStream.flush(); |
| 106 | File->os() << Buffer; |
| 107 | } |
| 108 | |
| 109 | void BackendPrinter::printInstructionInfo() const { |
| 110 | std::string Buffer; |
| 111 | raw_string_ostream TempStream(Buffer); |
| 112 | |
| 113 | TempStream << "\n\nInstruction Info:\n"; |
| 114 | TempStream << "[1]: #uOps\n[2]: Latency\n[3]: RThroughput\n" |
| 115 | << "[4]: MayLoad\n[5]: MayStore\n[6]: HasSideEffects\n\n"; |
| 116 | |
| 117 | TempStream << "[1] [2] [3] [4] [5] [6]\tInstructions:\n"; |
| 118 | for (unsigned I = 0, E = B.getNumInstructions(); I < E; ++I) { |
| 119 | const MCInst &Inst = B.getMCInstFromIndex(I); |
| 120 | const InstrDesc &ID = B.getInstrDesc(Inst); |
| 121 | unsigned NumMicroOpcodes = ID.NumMicroOps; |
| 122 | unsigned Latency = ID.MaxLatency; |
| 123 | double RThroughput = B.getRThroughput(ID); |
| 124 | TempStream << ' ' << NumMicroOpcodes << " "; |
| 125 | if (NumMicroOpcodes < 10) |
| 126 | TempStream << " "; |
| 127 | else if (NumMicroOpcodes < 100) |
| 128 | TempStream << ' '; |
| 129 | TempStream << Latency << " "; |
| 130 | if (Latency < 10.0) |
| 131 | TempStream << " "; |
| 132 | else if (Latency < 100.0) |
| 133 | TempStream << ' '; |
| 134 | if (RThroughput) { |
| 135 | TempStream << format("%.2f", RThroughput) << ' '; |
| 136 | if (RThroughput < 10.0) |
| 137 | TempStream << " "; |
| 138 | else if (RThroughput < 100.0) |
| 139 | TempStream << ' '; |
| 140 | } else { |
| 141 | TempStream << " - "; |
| 142 | } |
| 143 | TempStream << (ID.MayLoad ? " * " : " "); |
| 144 | TempStream << (ID.MayStore ? " * " : " "); |
| 145 | TempStream << (ID.HasSideEffects ? " * " : " "); |
| 146 | MCIP->printInst(&Inst, TempStream, "", B.getSTI()); |
| 147 | TempStream << '\n'; |
| 148 | } |
| 149 | |
| 150 | TempStream.flush(); |
| 151 | File->os() << Buffer; |
| 152 | } |
| 153 | |
| 154 | void BackendPrinter::printReport() const { |
| 155 | assert(isFileValid()); |
| 156 | unsigned Cycles = B.getNumCycles(); |
| 157 | printGeneralStatistics(B.getNumIterations(), Cycles, B.getNumInstructions(), |
| 158 | B.getDispatchWidth()); |
| 159 | if (EnableVerboseOutput) { |
| 160 | printDispatchStalls(B.getNumRATStalls(), B.getNumRCUStalls(), |
| 161 | B.getNumSQStalls(), B.getNumLDQStalls(), |
| 162 | B.getNumSTQStalls(), B.getNumDispatchGroupStalls()); |
| 163 | printRATStatistics(B.getTotalRegisterMappingsCreated(), |
| 164 | B.getMaxUsedRegisterMappings()); |
| 165 | BS->printHistograms(File->os()); |
| 166 | |
| 167 | std::vector<BufferUsageEntry> Usage; |
| 168 | B.getBuffersUsage(Usage); |
| 169 | printSchedulerUsage(B.getSchedModel(), Usage); |
| 170 | } |
| 171 | |
| 172 | if (RPV) { |
| 173 | RPV->printResourcePressure(getOStream(), Cycles); |
| 174 | printInstructionInfo(); |
| 175 | } |
| 176 | |
| 177 | if (TV) { |
| 178 | TV->printTimeline(getOStream()); |
| 179 | TV->printAverageWaitTimes(getOStream()); |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | void BackendPrinter::addResourcePressureView() { |
| 184 | if (!RPV) { |
| 185 | RPV = llvm::make_unique<ResourcePressureView>( |
| 186 | B.getSTI(), *MCIP, B.getSourceMgr(), B.getProcResourceMasks()); |
| 187 | B.addEventListener(RPV.get()); |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | void BackendPrinter::addTimelineView(unsigned MaxIterations, |
| 192 | unsigned MaxCycles) { |
| 193 | if (!TV) { |
| 194 | TV = llvm::make_unique<TimelineView>(B.getSTI(), *MCIP, B.getSourceMgr(), |
| 195 | MaxIterations, MaxCycles); |
| 196 | B.addEventListener(TV.get()); |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | void BackendPrinter::initialize(std::string OutputFileName) { |
| 201 | File = getOutputStream(OutputFileName); |
| 202 | MCIP->setPrintImmHex(false); |
| 203 | if (EnableVerboseOutput) { |
| 204 | BS = llvm::make_unique<BackendStatistics>(); |
| 205 | B.addEventListener(BS.get()); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | } // namespace mca. |