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 static void printInstructionRow(const InstructionBenchmark &Point, 38 const llvm::MCSubtargetInfo &STI, 39 const size_t ClusterId, llvm::raw_ostream &OS) { 40 OS << ClusterId << kCsvSep; 41 writeCsvEscaped(OS, Point.Key.OpcodeName); 42 OS << kCsvSep; 43 writeCsvEscaped(OS, Point.Key.Config); 44 // FIXME: Print the sched class once InstructionBenchmark separates key into 45 // (mnemonic, mode, opaque). 46 for (const auto &Measurement : Point.Measurements) { 47 OS << kCsvSep; 48 writeCsvEscaped(OS, llvm::formatv("{0:F}", Measurement.Value)); 49 } 50 OS << "\n"; 51 } 52 53 static void printCluster(const std::vector<InstructionBenchmark> &Points, 54 const llvm::MCSubtargetInfo &STI, 55 const size_t ClusterId, 56 const InstructionBenchmarkClustering::Cluster &Cluster, 57 llvm::raw_ostream &OS) { 58 // Print all points. 59 for (const auto &PointId : Cluster.PointIndices) { 60 printInstructionRow(Points[PointId], STI, ClusterId, OS); 61 } 62 } 63 64 llvm::Error 65 printAnalysisClusters(const InstructionBenchmarkClustering &Clustering, 66 const llvm::MCSubtargetInfo &STI, llvm::raw_ostream &OS) { 67 if (Clustering.getPoints().empty()) 68 return llvm::Error::success(); 69 70 // Write the header. 71 OS << "cluster_id" << kCsvSep << "opcode_name" << kCsvSep << "config" 72 << kCsvSep << "sched_class"; 73 for (const auto &Measurement : Clustering.getPoints().front().Measurements) { 74 OS << kCsvSep; 75 writeCsvEscaped(OS, Measurement.Key); 76 } 77 OS << "\n"; 78 79 // Write the points. 80 for (size_t I = 0, E = Clustering.getValidClusters().size(); I < E; ++I) { 81 printCluster(Clustering.getPoints(), STI, I, 82 Clustering.getValidClusters()[I], OS); 83 OS << "\n\n"; 84 } 85 return llvm::Error::success(); 86 } 87 88 } // namespace exegesis 89