xref: /llvm-project/llvm/tools/llvm-exegesis/lib/Analysis.cpp (revision 4022b6c42f3d22a1973e6d461b82060be26245d2)
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