blob: a02ea29e3d177a580cb49dd6e22d62066dcbd6ed [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 Courbetcf210742018-05-17 13:41:28 +000094template <>
95llvm::Error
96Analysis::run<Analysis::PrintClusters>(llvm::raw_ostream &OS) const {
Clement Courbet6d6c1a92018-05-16 08:47:21 +000097 if (Clustering_.getPoints().empty())
Clement Courbet37f0ca02018-05-15 12:08:00 +000098 return llvm::Error::success();
99
100 // Write the header.
Clement Courbeta66bfaa42018-05-15 13:07:05 +0000101 OS << "cluster_id" << kCsvSep << "opcode_name" << kCsvSep << "config"
102 << kCsvSep << "sched_class";
Clement Courbet6d6c1a92018-05-16 08:47:21 +0000103 for (const auto &Measurement : Clustering_.getPoints().front().Measurements) {
Clement Courbet37f0ca02018-05-15 12:08:00 +0000104 OS << kCsvSep;
105 writeCsvEscaped(OS, Measurement.Key);
106 }
107 OS << "\n";
108
109 // Write the points.
Clement Courbet448550d2018-05-17 12:25:18 +0000110 const auto &Clusters = Clustering_.getValidClusters();
Clement Courbet6d6c1a92018-05-16 08:47:21 +0000111 for (size_t I = 0, E = Clusters.size(); I < E; ++I) {
112 for (const size_t PointId : Clusters[I].PointIndices) {
Clement Courbet448550d2018-05-17 12:25:18 +0000113 printInstructionRow(/*PrintSchedClass*/ true, PointId, OS);
Clement Courbet6d6c1a92018-05-16 08:47:21 +0000114 }
Clement Courbet37f0ca02018-05-15 12:08:00 +0000115 OS << "\n\n";
116 }
117 return llvm::Error::success();
118}
119
Clement Courbet448550d2018-05-17 12:25:18 +0000120std::unordered_map<unsigned, std::vector<size_t>>
121Analysis::makePointsPerSchedClass() const {
122 std::unordered_map<unsigned, std::vector<size_t>> PointsPerSchedClass;
123 const auto &Points = Clustering_.getPoints();
124 for (size_t PointId = 0, E = Points.size(); PointId < E; ++PointId) {
125 const InstructionBenchmark &Point = Points[PointId];
126 if (!Point.Error.empty())
127 continue;
128 const auto OpcodeIt = MnemonicToOpcode_.find(Point.Key.OpcodeName);
129 if (OpcodeIt == MnemonicToOpcode_.end())
130 continue;
131 const unsigned SchedClassId =
132 InstrInfo_->get(OpcodeIt->second).getSchedClass();
133 PointsPerSchedClass[SchedClassId].push_back(PointId);
134 }
135 return PointsPerSchedClass;
136}
137
Clement Courbetcf210742018-05-17 13:41:28 +0000138template <>
139llvm::Error Analysis::run<Analysis::PrintSchedClassInconsistencies>(
140 llvm::raw_ostream &OS) const {
Clement Courbet448550d2018-05-17 12:25:18 +0000141 // All the points in a scheduling class should be in the same cluster.
142 // Print any scheduling class for which this is not the case.
143 for (const auto &SchedClassAndPoints : makePointsPerSchedClass()) {
144 std::unordered_set<size_t> ClustersForSchedClass;
145 for (const size_t PointId : SchedClassAndPoints.second) {
146 const auto &ClusterId = Clustering_.getClusterIdForPoint(PointId);
147 if (!ClusterId.isValid())
148 continue; // Ignore noise and errors.
149 ClustersForSchedClass.insert(ClusterId.getId());
150 }
151 if (ClustersForSchedClass.size() <= 1)
152 continue; // Nothing weird.
153
154 OS << "\nSched Class ";
155#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
156 const auto &SchedModel = SubtargetInfo_->getSchedModel();
157 const llvm::MCSchedClassDesc *const SCDesc =
158 SchedModel.getSchedClassDesc(SchedClassAndPoints.first);
159 OS << SCDesc->Name;
160#else
161 OS << SchedClassAndPoints.first;
162#endif
163 OS << " contains instructions with distinct performance "
164 "characteristics, falling into "
165 << ClustersForSchedClass.size() << " clusters:\n";
166 for (const size_t PointId : SchedClassAndPoints.second) {
167 printInstructionRow(/*PrintSchedClass*/ false, PointId, OS);
168 }
169 }
170 return llvm::Error::success();
171}
172
Clement Courbetcf210742018-05-17 13:41:28 +0000173template llvm::Error
174Analysis::run<Analysis::PrintClusters>(llvm::raw_ostream &OS) const;
175template llvm::Error Analysis::run<Analysis::PrintSchedClassInconsistencies>(
176 llvm::raw_ostream &OS) const;
177
Clement Courbet37f0ca02018-05-15 12:08:00 +0000178} // namespace exegesis