blob: 5b609257f59f8250980fef8e08f75a1482032f3a [file] [log] [blame]
Clement Courbet37f0ca02018-05-15 12:08:00 +00001//===-- 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
Clement Courbet37f0ca02018-05-15 12:08:00 +000010#include "Analysis.h"
Clement Courbeta66bfaa42018-05-15 13:07:05 +000011#include "BenchmarkResult.h"
Clement Courbet37f0ca02018-05-15 12:08:00 +000012#include "llvm/Support/FormatVariadic.h"
Clement Courbet448550d2018-05-17 12:25:18 +000013#include <unordered_set>
Clement Courbet37f0ca02018-05-15 12:08:00 +000014#include <vector>
15
16namespace exegesis {
17
18static const char kCsvSep = ',';
19
Clement Courbeta66bfaa42018-05-15 13:07:05 +000020static void writeCsvEscaped(llvm::raw_ostream &OS, const std::string &S) {
Clement Courbet37f0ca02018-05-15 12:08:00 +000021 if (std::find(S.begin(), S.end(), kCsvSep) == S.end()) {
22 OS << S;
23 } else {
24 // Needs escaping.
25 OS << '"';
26 for (const char C : S) {
27 if (C == '"')
28 OS << "\"\"";
29 else
30 OS << C;
31 }
32 OS << '"';
33 }
34}
35
36// Prints a row representing an instruction, along with scheduling info and
37// point coordinates (measurements).
Clement Courbet448550d2018-05-17 12:25:18 +000038void Analysis::printInstructionRow(const bool PrintSchedClass,
39 const size_t PointId,
Clement Courbet6d6c1a92018-05-16 08:47:21 +000040 llvm::raw_ostream &OS) const {
41 const InstructionBenchmark &Point = Clustering_.getPoints()[PointId];
Clement Courbet448550d2018-05-17 12:25:18 +000042 const auto &ClusterId = Clustering_.getClusterIdForPoint(PointId);
43 if (ClusterId.isNoise())
44 OS << "[noise]";
45 else if (ClusterId.isError())
46 OS << "[error]";
47 else
48 OS << ClusterId.getId();
49 OS << kCsvSep;
Clement Courbeta66bfaa42018-05-15 13:07:05 +000050 writeCsvEscaped(OS, Point.Key.OpcodeName);
51 OS << kCsvSep;
52 writeCsvEscaped(OS, Point.Key.Config);
Clement Courbet448550d2018-05-17 12:25:18 +000053 if (PrintSchedClass) {
54 OS << kCsvSep;
55 const auto OpcodeIt = MnemonicToOpcode_.find(Point.Key.OpcodeName);
56 if (OpcodeIt != MnemonicToOpcode_.end()) {
57 const unsigned SchedClassId =
58 InstrInfo_->get(OpcodeIt->second).getSchedClass();
Clement Courbet6d6c1a92018-05-16 08:47:21 +000059#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
Clement Courbet448550d2018-05-17 12:25:18 +000060 const auto &SchedModel = SubtargetInfo_->getSchedModel();
61 const llvm::MCSchedClassDesc *const SCDesc =
62 SchedModel.getSchedClassDesc(SchedClassId);
63 writeCsvEscaped(OS, SCDesc->Name);
Clement Courbet6d6c1a92018-05-16 08:47:21 +000064#else
Clement Courbet448550d2018-05-17 12:25:18 +000065 OS << SchedClassId;
Clement Courbet6d6c1a92018-05-16 08:47:21 +000066#endif
Clement Courbet448550d2018-05-17 12:25:18 +000067 }
Clement Courbet6d6c1a92018-05-16 08:47:21 +000068 }
Clement Courbet37f0ca02018-05-15 12:08:00 +000069 // FIXME: Print the sched class once InstructionBenchmark separates key into
70 // (mnemonic, mode, opaque).
71 for (const auto &Measurement : Point.Measurements) {
72 OS << kCsvSep;
73 writeCsvEscaped(OS, llvm::formatv("{0:F}", Measurement.Value));
74 }
75 OS << "\n";
76}
77
Clement Courbet6d6c1a92018-05-16 08:47:21 +000078Analysis::Analysis(const llvm::Target &Target,
79 const InstructionBenchmarkClustering &Clustering)
80 : Clustering_(Clustering) {
81 if (Clustering.getPoints().empty())
82 return;
83
84 InstrInfo_.reset(Target.createMCInstrInfo());
85 const InstructionBenchmark &FirstPoint = Clustering.getPoints().front();
Clement Courbet448550d2018-05-17 12:25:18 +000086 SubtargetInfo_.reset(Target.createMCSubtargetInfo(FirstPoint.LLVMTriple,
87 FirstPoint.CpuName, ""));
Clement Courbet6d6c1a92018-05-16 08:47:21 +000088
89 // Build an index of mnemonic->opcode.
90 for (int I = 0, E = InstrInfo_->getNumOpcodes(); I < E; ++I)
91 MnemonicToOpcode_.emplace(InstrInfo_->getName(I), I);
Clement Courbet37f0ca02018-05-15 12:08:00 +000092}
93
Clement Courbet6d6c1a92018-05-16 08:47:21 +000094llvm::Error Analysis::printClusters(llvm::raw_ostream &OS) const {
95 if (Clustering_.getPoints().empty())
Clement Courbet37f0ca02018-05-15 12:08:00 +000096 return llvm::Error::success();
97
98 // Write the header.
Clement Courbeta66bfaa42018-05-15 13:07:05 +000099 OS << "cluster_id" << kCsvSep << "opcode_name" << kCsvSep << "config"
100 << kCsvSep << "sched_class";
Clement Courbet6d6c1a92018-05-16 08:47:21 +0000101 for (const auto &Measurement : Clustering_.getPoints().front().Measurements) {
Clement Courbet37f0ca02018-05-15 12:08:00 +0000102 OS << kCsvSep;
103 writeCsvEscaped(OS, Measurement.Key);
104 }
105 OS << "\n";
106
107 // Write the points.
Clement Courbet448550d2018-05-17 12:25:18 +0000108 const auto &Clusters = Clustering_.getValidClusters();
Clement Courbet6d6c1a92018-05-16 08:47:21 +0000109 for (size_t I = 0, E = Clusters.size(); I < E; ++I) {
110 for (const size_t PointId : Clusters[I].PointIndices) {
Clement Courbet448550d2018-05-17 12:25:18 +0000111 printInstructionRow(/*PrintSchedClass*/ true, PointId, OS);
Clement Courbet6d6c1a92018-05-16 08:47:21 +0000112 }
Clement Courbet37f0ca02018-05-15 12:08:00 +0000113 OS << "\n\n";
114 }
115 return llvm::Error::success();
116}
117
Clement Courbet448550d2018-05-17 12:25:18 +0000118std::unordered_map<unsigned, std::vector<size_t>>
119Analysis::makePointsPerSchedClass() const {
120 std::unordered_map<unsigned, std::vector<size_t>> PointsPerSchedClass;
121 const auto &Points = Clustering_.getPoints();
122 for (size_t PointId = 0, E = Points.size(); PointId < E; ++PointId) {
123 const InstructionBenchmark &Point = Points[PointId];
124 if (!Point.Error.empty())
125 continue;
126 const auto OpcodeIt = MnemonicToOpcode_.find(Point.Key.OpcodeName);
127 if (OpcodeIt == MnemonicToOpcode_.end())
128 continue;
129 const unsigned SchedClassId =
130 InstrInfo_->get(OpcodeIt->second).getSchedClass();
131 PointsPerSchedClass[SchedClassId].push_back(PointId);
132 }
133 return PointsPerSchedClass;
134}
135
136llvm::Error
137Analysis::printSchedClassInconsistencies(llvm::raw_ostream &OS) const {
138 // All the points in a scheduling class should be in the same cluster.
139 // Print any scheduling class for which this is not the case.
140 for (const auto &SchedClassAndPoints : makePointsPerSchedClass()) {
141 std::unordered_set<size_t> ClustersForSchedClass;
142 for (const size_t PointId : SchedClassAndPoints.second) {
143 const auto &ClusterId = Clustering_.getClusterIdForPoint(PointId);
144 if (!ClusterId.isValid())
145 continue; // Ignore noise and errors.
146 ClustersForSchedClass.insert(ClusterId.getId());
147 }
148 if (ClustersForSchedClass.size() <= 1)
149 continue; // Nothing weird.
150
151 OS << "\nSched Class ";
152#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
153 const auto &SchedModel = SubtargetInfo_->getSchedModel();
154 const llvm::MCSchedClassDesc *const SCDesc =
155 SchedModel.getSchedClassDesc(SchedClassAndPoints.first);
156 OS << SCDesc->Name;
157#else
158 OS << SchedClassAndPoints.first;
159#endif
160 OS << " contains instructions with distinct performance "
161 "characteristics, falling into "
162 << ClustersForSchedClass.size() << " clusters:\n";
163 for (const size_t PointId : SchedClassAndPoints.second) {
164 printInstructionRow(/*PrintSchedClass*/ false, PointId, OS);
165 }
166 }
167 return llvm::Error::success();
168}
169
Clement Courbet37f0ca02018-05-15 12:08:00 +0000170} // namespace exegesis