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