1 //===-- Analysis.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 10 #include "Analysis.h" 11 #include "BenchmarkResult.h" 12 #include "llvm/Support/FormatVariadic.h" 13 #include <vector> 14 15 namespace exegesis { 16 17 static const char kCsvSep = ','; 18 19 static void writeCsvEscaped(llvm::raw_ostream &OS, const std::string &S) { 20 if (std::find(S.begin(), S.end(), kCsvSep) == S.end()) { 21 OS << S; 22 } else { 23 // Needs escaping. 24 OS << '"'; 25 for (const char C : S) { 26 if (C == '"') 27 OS << "\"\""; 28 else 29 OS << C; 30 } 31 OS << '"'; 32 } 33 } 34 35 // Prints a row representing an instruction, along with scheduling info and 36 // point coordinates (measurements). 37 void Analysis::printInstructionRow(const size_t ClusterId, const size_t PointId, 38 llvm::raw_ostream &OS) const { 39 const InstructionBenchmark &Point = Clustering_.getPoints()[PointId]; 40 41 OS << ClusterId << kCsvSep; 42 writeCsvEscaped(OS, Point.Key.OpcodeName); 43 OS << kCsvSep; 44 writeCsvEscaped(OS, Point.Key.Config); 45 OS << kCsvSep; 46 const auto OpcodeIt = MnemonicToOpcode_.find(Point.Key.OpcodeName); 47 if (OpcodeIt != MnemonicToOpcode_.end()) { 48 const auto &SchedModel = SubtargetInfo_->getSchedModel(); 49 const unsigned SchedClassId = InstrInfo_->get(OpcodeIt->second).getSchedClass(); 50 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 51 const llvm::MCSchedClassDesc *const SCDesc = 52 SchedModel.getSchedClassDesc(SchedClassId); 53 writeCsvEscaped(OS, SCDesc->Name); 54 #else 55 OS << SchedClassId; 56 #endif 57 } 58 // FIXME: Print the sched class once InstructionBenchmark separates key into 59 // (mnemonic, mode, opaque). 60 for (const auto &Measurement : Point.Measurements) { 61 OS << kCsvSep; 62 writeCsvEscaped(OS, llvm::formatv("{0:F}", Measurement.Value)); 63 } 64 OS << "\n"; 65 } 66 67 Analysis::Analysis(const llvm::Target &Target, 68 const InstructionBenchmarkClustering &Clustering) 69 : Clustering_(Clustering) { 70 if (Clustering.getPoints().empty()) 71 return; 72 73 InstrInfo_.reset(Target.createMCInstrInfo()); 74 const InstructionBenchmark &FirstPoint = Clustering.getPoints().front(); 75 SubtargetInfo_.reset(Target.createMCSubtargetInfo( 76 FirstPoint.LLVMTriple, FirstPoint.CpuName, "")); 77 78 // Build an index of mnemonic->opcode. 79 for (int I = 0, E = InstrInfo_->getNumOpcodes(); I < E; ++I) 80 MnemonicToOpcode_.emplace(InstrInfo_->getName(I), I); 81 } 82 83 llvm::Error Analysis::printClusters(llvm::raw_ostream &OS) const { 84 if (Clustering_.getPoints().empty()) 85 return llvm::Error::success(); 86 87 // Write the header. 88 OS << "cluster_id" << kCsvSep << "opcode_name" << kCsvSep << "config" 89 << kCsvSep << "sched_class"; 90 for (const auto &Measurement : Clustering_.getPoints().front().Measurements) { 91 OS << kCsvSep; 92 writeCsvEscaped(OS, Measurement.Key); 93 } 94 OS << "\n"; 95 96 // Write the points. 97 const auto& Clusters = Clustering_.getValidClusters(); 98 for (size_t I = 0, E = Clusters.size(); I < E; ++I) { 99 for (const size_t PointId : Clusters[I].PointIndices) { 100 printInstructionRow(I, PointId, OS); 101 } 102 OS << "\n\n"; 103 } 104 return llvm::Error::success(); 105 } 106 107 } // namespace exegesis 108