blob: bbc1c9ba28cfe7c60d1716ac806aa83a8ee9a1af [file] [log] [blame]
Clement Courbetac74acd2018-04-04 11:37:06 +00001//===-- llvm-exegesis.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/// \file
11/// Measures execution properties (latencies/uops) of an instruction.
12///
13//===----------------------------------------------------------------------===//
14
Clement Courbet37f0ca02018-05-15 12:08:00 +000015#include "lib/Analysis.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000016#include "lib/BenchmarkResult.h"
17#include "lib/BenchmarkRunner.h"
Clement Courbet37f0ca02018-05-15 12:08:00 +000018#include "lib/Clustering.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000019#include "lib/LlvmState.h"
20#include "lib/PerfHelper.h"
Clement Courbet4860b982018-06-26 08:49:30 +000021#include "lib/Target.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000022#include "llvm/ADT/StringExtras.h"
23#include "llvm/ADT/Twine.h"
24#include "llvm/MC/MCInstBuilder.h"
Clement Courbet78b2e732018-09-25 07:31:44 +000025#include "llvm/MC/MCObjectFileInfo.h"
26#include "llvm/MC/MCParser/MCAsmParser.h"
27#include "llvm/MC/MCParser/MCTargetAsmParser.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000028#include "llvm/MC/MCRegisterInfo.h"
Clement Courbet78b2e732018-09-25 07:31:44 +000029#include "llvm/MC/MCStreamer.h"
Clement Courbet37f0ca02018-05-15 12:08:00 +000030#include "llvm/MC/MCSubtargetInfo.h"
Clement Courbet78b2e732018-09-25 07:31:44 +000031#include "llvm/Object/ObjectFile.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000032#include "llvm/Support/CommandLine.h"
Clement Courbet37f0ca02018-05-15 12:08:00 +000033#include "llvm/Support/Format.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000034#include "llvm/Support/Path.h"
Clement Courbet78b2e732018-09-25 07:31:44 +000035#include "llvm/Support/SourceMgr.h"
Clement Courbet37f0ca02018-05-15 12:08:00 +000036#include "llvm/Support/TargetRegistry.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000037#include "llvm/Support/TargetSelect.h"
38#include <algorithm>
Clement Courbetac74acd2018-04-04 11:37:06 +000039#include <string>
Clement Courbetac74acd2018-04-04 11:37:06 +000040
Clement Courbetf973c2d2018-10-17 15:04:15 +000041static llvm::cl::opt<int>
Clement Courbetac74acd2018-04-04 11:37:06 +000042 OpcodeIndex("opcode-index", llvm::cl::desc("opcode to measure, by index"),
43 llvm::cl::init(0));
44
Clement Courbetf973c2d2018-10-17 15:04:15 +000045static llvm::cl::opt<std::string> OpcodeNames(
46 "opcode-name",
47 llvm::cl::desc("comma-separated list of opcodes to measure, by name"),
48 llvm::cl::init(""));
Clement Courbetac74acd2018-04-04 11:37:06 +000049
Clement Courbet37f0ca02018-05-15 12:08:00 +000050static llvm::cl::opt<std::string>
Clement Courbet78b2e732018-09-25 07:31:44 +000051 SnippetsFile("snippets-file", llvm::cl::desc("code snippets to measure"),
52 llvm::cl::init(""));
53
54static llvm::cl::opt<std::string>
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +000055 BenchmarkFile("benchmarks-file", llvm::cl::desc(""), llvm::cl::init(""));
Clement Courbet37f0ca02018-05-15 12:08:00 +000056
Clement Courbet4860b982018-06-26 08:49:30 +000057static llvm::cl::opt<exegesis::InstructionBenchmark::ModeE> BenchmarkMode(
Clement Courbet5ec03cd2018-05-18 12:33:57 +000058 "mode", llvm::cl::desc("the mode to run"),
Clement Courbet4860b982018-06-26 08:49:30 +000059 llvm::cl::values(clEnumValN(exegesis::InstructionBenchmark::Latency,
60 "latency", "Instruction Latency"),
61 clEnumValN(exegesis::InstructionBenchmark::Uops, "uops",
62 "Uop Decomposition"),
63 // When not asking for a specific benchmark mode, we'll
64 // analyse the results.
65 clEnumValN(exegesis::InstructionBenchmark::Unknown,
66 "analysis", "Analysis")));
Clement Courbetac74acd2018-04-04 11:37:06 +000067
68static llvm::cl::opt<unsigned>
69 NumRepetitions("num-repetitions",
70 llvm::cl::desc("number of time to repeat the asm snippet"),
71 llvm::cl::init(10000));
72
Clement Courbete752fd62018-06-18 11:27:47 +000073static llvm::cl::opt<bool> IgnoreInvalidSchedClass(
74 "ignore-invalid-sched-class",
75 llvm::cl::desc("ignore instructions that do not define a sched class"),
76 llvm::cl::init(false));
77
Clement Courbet37f0ca02018-05-15 12:08:00 +000078static llvm::cl::opt<unsigned> AnalysisNumPoints(
79 "analysis-numpoints",
80 llvm::cl::desc("minimum number of points in an analysis cluster"),
81 llvm::cl::init(3));
82
83static llvm::cl::opt<float>
84 AnalysisEpsilon("analysis-epsilon",
85 llvm::cl::desc("dbscan epsilon for analysis clustering"),
86 llvm::cl::init(0.1));
87
Clement Courbetcf210742018-05-17 13:41:28 +000088static llvm::cl::opt<std::string>
89 AnalysisClustersOutputFile("analysis-clusters-output-file",
90 llvm::cl::desc(""), llvm::cl::init("-"));
91static llvm::cl::opt<std::string>
92 AnalysisInconsistenciesOutputFile("analysis-inconsistencies-output-file",
93 llvm::cl::desc(""), llvm::cl::init("-"));
Clement Courbetcaa163e2018-05-16 09:50:04 +000094
Clement Courbetac74acd2018-04-04 11:37:06 +000095namespace exegesis {
96
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +000097static llvm::ExitOnError ExitOnErr;
98
Clement Courbet44b4c542018-06-19 11:28:59 +000099#ifdef LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET
100void LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET();
101#endif
102
Clement Courbetf973c2d2018-10-17 15:04:15 +0000103// Checks that only one of OpcodeNames, OpcodeIndex or SnippetsFile is provided,
104// and returns the opcode indices or {} if snippets should be read from
Clement Courbet78b2e732018-09-25 07:31:44 +0000105// `SnippetsFile`.
Clement Courbetf973c2d2018-10-17 15:04:15 +0000106static std::vector<unsigned>
107getOpcodesOrDie(const llvm::MCInstrInfo &MCInstrInfo) {
108 const size_t NumSetFlags = (OpcodeNames.empty() ? 0 : 1) +
Clement Courbet78b2e732018-09-25 07:31:44 +0000109 (OpcodeIndex == 0 ? 0 : 1) +
110 (SnippetsFile.empty() ? 0 : 1);
111 if (NumSetFlags != 1)
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000112 llvm::report_fatal_error(
Clement Courbet78b2e732018-09-25 07:31:44 +0000113 "please provide one and only one of 'opcode-index', 'opcode-name' or "
114 "'snippets-file'");
115 if (!SnippetsFile.empty())
Clement Courbetf973c2d2018-10-17 15:04:15 +0000116 return {};
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000117 if (OpcodeIndex > 0)
Clement Courbetf973c2d2018-10-17 15:04:15 +0000118 return {static_cast<unsigned>(OpcodeIndex)};
119 if (OpcodeIndex < 0) {
120 std::vector<unsigned> Result;
Guillaume Chatelet6a208e82018-10-18 08:20:50 +0000121 for (unsigned I = 1, E = MCInstrInfo.getNumOpcodes(); I < E; ++I)
Clement Courbetf973c2d2018-10-17 15:04:15 +0000122 Result.push_back(I);
123 return Result;
124 }
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000125 // Resolve opcode name -> opcode.
Clement Courbetf973c2d2018-10-17 15:04:15 +0000126 const auto ResolveName =
127 [&MCInstrInfo](llvm::StringRef OpcodeName) -> unsigned {
128 for (unsigned I = 1, E = MCInstrInfo.getNumOpcodes(); I < E; ++I)
129 if (MCInstrInfo.getName(I) == OpcodeName)
130 return I;
131 return 0u;
132 };
133 llvm::SmallVector<llvm::StringRef, 2> Pieces;
134 llvm::StringRef(OpcodeNames.getValue())
135 .split(Pieces, ",", /* MaxSplit */ -1, /* KeepEmpty */ false);
136 std::vector<unsigned> Result;
137 for (const llvm::StringRef OpcodeName : Pieces) {
138 if (unsigned Opcode = ResolveName(OpcodeName))
139 Result.push_back(Opcode);
140 else
141 llvm::report_fatal_error(
142 llvm::Twine("unknown opcode ").concat(OpcodeName));
143 }
144 return Result;
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000145}
146
Clement Courbetd939f6d2018-09-13 07:40:53 +0000147// Generates code snippets for opcode `Opcode`.
Clement Courbet78b2e732018-09-25 07:31:44 +0000148static llvm::Expected<std::vector<BenchmarkCode>>
Clement Courbet79587352018-09-13 08:06:29 +0000149generateSnippets(const LLVMState &State, unsigned Opcode) {
Guillaume Chatelet9b592382018-10-10 14:57:32 +0000150 const Instruction Instr(State, Opcode);
151 const llvm::MCInstrDesc &InstrDesc = *Instr.Description;
Clement Courbetd939f6d2018-09-13 07:40:53 +0000152 // Ignore instructions that we cannot run.
153 if (InstrDesc.isPseudo())
154 return llvm::make_error<BenchmarkFailure>("Unsupported opcode: isPseudo");
155 if (InstrDesc.isBranch() || InstrDesc.isIndirectBranch())
156 return llvm::make_error<BenchmarkFailure>(
157 "Unsupported opcode: isBranch/isIndirectBranch");
158 if (InstrDesc.isCall() || InstrDesc.isReturn())
159 return llvm::make_error<BenchmarkFailure>(
160 "Unsupported opcode: isCall/isReturn");
161
Guillaume Chatelet9b592382018-10-10 14:57:32 +0000162 const std::unique_ptr<SnippetGenerator> Generator =
163 State.getExegesisTarget().createSnippetGenerator(BenchmarkMode, State);
164 if (!Generator)
165 llvm::report_fatal_error("cannot create snippet generator");
166 return Generator->generateConfigurations(Instr);
Clement Courbetd939f6d2018-09-13 07:40:53 +0000167}
168
Clement Courbet78b2e732018-09-25 07:31:44 +0000169namespace {
170
171// An MCStreamer that reads a BenchmarkCode definition from a file.
172// The BenchmarkCode definition is just an asm file, with additional comments to
173// specify which registers should be defined or are live on entry.
174class BenchmarkCodeStreamer : public llvm::MCStreamer,
175 public llvm::AsmCommentConsumer {
176public:
177 explicit BenchmarkCodeStreamer(llvm::MCContext *Context,
178 const llvm::MCRegisterInfo *TheRegInfo,
179 BenchmarkCode *Result)
180 : llvm::MCStreamer(*Context), RegInfo(TheRegInfo), Result(Result) {}
181
182 // Implementation of the llvm::MCStreamer interface. We only care about
183 // instructions.
Fangrui Song22438a82018-09-27 06:10:15 +0000184 void EmitInstruction(const llvm::MCInst &Instruction,
185 const llvm::MCSubtargetInfo &STI,
Clement Courbet78b2e732018-09-25 07:31:44 +0000186 bool PrintSchedInfo) override {
Fangrui Song22438a82018-09-27 06:10:15 +0000187 Result->Instructions.push_back(Instruction);
Clement Courbet78b2e732018-09-25 07:31:44 +0000188 }
189
190 // Implementation of the llvm::AsmCommentConsumer.
191 void HandleComment(llvm::SMLoc Loc, llvm::StringRef CommentText) override {
192 CommentText = CommentText.trim();
193 if (!CommentText.consume_front("LLVM-EXEGESIS-"))
194 return;
195 if (CommentText.consume_front("DEFREG")) {
196 // LLVM-EXEGESIS-DEFREF <reg> <hex_value>
197 RegisterValue RegVal;
198 llvm::SmallVector<llvm::StringRef, 2> Parts;
199 CommentText.split(Parts, ' ', /*unlimited splits*/ -1,
200 /*do not keep empty strings*/ false);
201 if (Parts.size() != 2) {
202 llvm::errs() << "invalid comment 'LLVM-EXEGESIS-DEFREG " << CommentText
203 << "\n";
204 ++InvalidComments;
205 }
206 if (!(RegVal.Register = findRegisterByName(Parts[0].trim()))) {
207 llvm::errs() << "unknown register in 'LLVM-EXEGESIS-DEFREG "
208 << CommentText << "\n";
209 ++InvalidComments;
210 return;
211 }
212 const llvm::StringRef HexValue = Parts[1].trim();
213 RegVal.Value = llvm::APInt(
214 /* each hex digit is 4 bits */ HexValue.size() * 4, HexValue, 16);
215 Result->RegisterInitialValues.push_back(std::move(RegVal));
216 return;
217 }
218 if (CommentText.consume_front("LIVEIN")) {
219 // LLVM-EXEGESIS-LIVEIN <reg>
220 if (unsigned Reg = findRegisterByName(CommentText.ltrim()))
221 Result->LiveIns.push_back(Reg);
222 else {
223 llvm::errs() << "unknown register in 'LLVM-EXEGESIS-LIVEIN "
224 << CommentText << "\n";
225 ++InvalidComments;
226 }
227 return;
228 }
229 }
230
231 unsigned numInvalidComments() const { return InvalidComments; }
232
233private:
234 // We only care about instructions, we don't implement this part of the API.
Fangrui Song22438a82018-09-27 06:10:15 +0000235 void EmitCommonSymbol(llvm::MCSymbol *Symbol, uint64_t Size,
236 unsigned ByteAlignment) override {}
237 bool EmitSymbolAttribute(llvm::MCSymbol *Symbol,
238 llvm::MCSymbolAttr Attribute) override {
Clement Courbet78b2e732018-09-25 07:31:44 +0000239 return false;
240 }
Fangrui Song22438a82018-09-27 06:10:15 +0000241 void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,
242 unsigned ValueSize,
243 unsigned MaxBytesToEmit) override {}
244 void EmitZerofill(llvm::MCSection *Section, llvm::MCSymbol *Symbol,
245 uint64_t Size, unsigned ByteAlignment,
Clement Courbet78b2e732018-09-25 07:31:44 +0000246 llvm::SMLoc Loc) override {}
247
248 unsigned findRegisterByName(const llvm::StringRef RegName) const {
249 // FIXME: Can we do better than this ?
250 for (unsigned I = 0, E = RegInfo->getNumRegs(); I < E; ++I) {
251 if (RegName == RegInfo->getName(I))
252 return I;
253 }
254 llvm::errs() << "'" << RegName
255 << "' is not a valid register name for the target\n";
256 return 0;
257 }
258
259 const llvm::MCRegisterInfo *const RegInfo;
260 BenchmarkCode *const Result;
261 unsigned InvalidComments = 0;
262};
263
264} // namespace
265
266// Reads code snippets from file `Filename`.
267static llvm::Expected<std::vector<BenchmarkCode>>
268readSnippets(const LLVMState &State, llvm::StringRef Filename) {
269 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferPtr =
270 llvm::MemoryBuffer::getFileOrSTDIN(Filename);
271 if (std::error_code EC = BufferPtr.getError()) {
272 return llvm::make_error<BenchmarkFailure>(
273 "cannot read snippet: " + Filename + ": " + EC.message());
274 }
275 llvm::SourceMgr SM;
276 SM.AddNewSourceBuffer(std::move(BufferPtr.get()), llvm::SMLoc());
277
278 BenchmarkCode Result;
279
280 llvm::MCObjectFileInfo ObjectFileInfo;
281 const llvm::TargetMachine &TM = State.getTargetMachine();
282 llvm::MCContext Context(TM.getMCAsmInfo(), TM.getMCRegisterInfo(),
283 &ObjectFileInfo);
284 ObjectFileInfo.InitMCObjectFileInfo(TM.getTargetTriple(), /*PIC*/ false,
285 Context);
286 BenchmarkCodeStreamer Streamer(&Context, TM.getMCRegisterInfo(), &Result);
287 const std::unique_ptr<llvm::MCAsmParser> AsmParser(
288 llvm::createMCAsmParser(SM, Context, Streamer, *TM.getMCAsmInfo()));
289 if (!AsmParser)
290 return llvm::make_error<BenchmarkFailure>("cannot create asm parser");
291 AsmParser->getLexer().setCommentConsumer(&Streamer);
292
293 const std::unique_ptr<llvm::MCTargetAsmParser> TargetAsmParser(
294 TM.getTarget().createMCAsmParser(*TM.getMCSubtargetInfo(), *AsmParser,
295 *TM.getMCInstrInfo(),
296 llvm::MCTargetOptions()));
297
298 if (!TargetAsmParser)
299 return llvm::make_error<BenchmarkFailure>(
300 "cannot create target asm parser");
301 AsmParser->setTargetParser(*TargetAsmParser);
302
303 if (AsmParser->Run(false))
304 return llvm::make_error<BenchmarkFailure>("cannot parse asm file");
305 if (Streamer.numInvalidComments())
306 return llvm::make_error<BenchmarkFailure>(
307 llvm::Twine("found ")
308 .concat(llvm::Twine(Streamer.numInvalidComments()))
309 .concat(" invalid LLVM-EXEGESIS comments"));
310 return std::vector<BenchmarkCode>{std::move(Result)};
311}
312
Clement Courbet37f0ca02018-05-15 12:08:00 +0000313void benchmarkMain() {
314 if (exegesis::pfm::pfmInitialize())
315 llvm::report_fatal_error("cannot initialize libpfm");
316
Clement Courbetac74acd2018-04-04 11:37:06 +0000317 llvm::InitializeNativeTarget();
318 llvm::InitializeNativeTargetAsmPrinter();
Clement Courbet78b2e732018-09-25 07:31:44 +0000319 llvm::InitializeNativeTargetAsmParser();
Clement Courbet44b4c542018-06-19 11:28:59 +0000320#ifdef LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET
321 LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET();
322#endif
Clement Courbetac74acd2018-04-04 11:37:06 +0000323
Clement Courbetac74acd2018-04-04 11:37:06 +0000324 const LLVMState State;
Clement Courbetf973c2d2018-10-17 15:04:15 +0000325 const auto Opcodes = getOpcodesOrDie(State.getInstrInfo());
Clement Courbete752fd62018-06-18 11:27:47 +0000326
Clement Courbet78b2e732018-09-25 07:31:44 +0000327 std::vector<BenchmarkCode> Configurations;
Clement Courbetf973c2d2018-10-17 15:04:15 +0000328 if (!Opcodes.empty()) {
329 for (const unsigned Opcode : Opcodes) {
330 // Ignore instructions without a sched class if
331 // -ignore-invalid-sched-class is passed.
332 if (IgnoreInvalidSchedClass &&
333 State.getInstrInfo().get(Opcode).getSchedClass() == 0) {
334 llvm::errs() << State.getInstrInfo().getName(Opcode)
335 << ": ignoring instruction without sched class\n";
336 continue;
337 }
338 auto ConfigsForInstr = generateSnippets(State, Opcode);
339 if (!ConfigsForInstr) {
340 llvm::logAllUnhandledErrors(
341 ConfigsForInstr.takeError(), llvm::errs(),
342 llvm::Twine(State.getInstrInfo().getName(Opcode)).concat(": "));
343 continue;
344 }
345 std::move(ConfigsForInstr->begin(), ConfigsForInstr->end(),
346 std::back_inserter(Configurations));
Clement Courbet78b2e732018-09-25 07:31:44 +0000347 }
Clement Courbet78b2e732018-09-25 07:31:44 +0000348 } else {
349 Configurations = ExitOnErr(readSnippets(State, SnippetsFile));
Clement Courbete752fd62018-06-18 11:27:47 +0000350 }
Clement Courbetac74acd2018-04-04 11:37:06 +0000351
Clement Courbet4860b982018-06-26 08:49:30 +0000352 const std::unique_ptr<BenchmarkRunner> Runner =
353 State.getExegesisTarget().createBenchmarkRunner(BenchmarkMode, State);
354 if (!Runner) {
355 llvm::report_fatal_error("cannot create benchmark runner");
Clement Courbetac74acd2018-04-04 11:37:06 +0000356 }
357
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000358 if (NumRepetitions == 0)
359 llvm::report_fatal_error("--num-repetitions must be greater than zero");
360
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000361 // Write to standard output if file is not set.
362 if (BenchmarkFile.empty())
363 BenchmarkFile = "-";
364
Clement Courbetd939f6d2018-09-13 07:40:53 +0000365 for (const BenchmarkCode &Conf : Configurations) {
366 InstructionBenchmark Result =
367 Runner->runConfiguration(Conf, NumRepetitions);
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000368 ExitOnErr(Result.writeYaml(State, BenchmarkFile));
Clement Courbetd939f6d2018-09-13 07:40:53 +0000369 }
Clement Courbet37f0ca02018-05-15 12:08:00 +0000370 exegesis::pfm::pfmTerminate();
371}
372
Clement Courbetcf210742018-05-17 13:41:28 +0000373// Prints the results of running analysis pass `Pass` to file `OutputFilename`
374// if OutputFilename is non-empty.
375template <typename Pass>
376static void maybeRunAnalysis(const Analysis &Analyzer, const std::string &Name,
Clement Courbet53d35d22018-06-05 10:56:19 +0000377 const std::string &OutputFilename) {
Clement Courbetcf210742018-05-17 13:41:28 +0000378 if (OutputFilename.empty())
379 return;
380 if (OutputFilename != "-") {
381 llvm::errs() << "Printing " << Name << " results to file '"
382 << OutputFilename << "'\n";
383 }
384 std::error_code ErrorCode;
385 llvm::raw_fd_ostream ClustersOS(OutputFilename, ErrorCode,
Zachary Turner1f67a3c2018-06-07 19:58:58 +0000386 llvm::sys::fs::FA_Read |
387 llvm::sys::fs::FA_Write);
388 if (ErrorCode)
389 llvm::report_fatal_error("cannot open out file: " + OutputFilename);
390 if (auto Err = Analyzer.run<Pass>(ClustersOS))
391 llvm::report_fatal_error(std::move(Err));
Clement Courbetcf210742018-05-17 13:41:28 +0000392}
393
394static void analysisMain() {
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000395 if (BenchmarkFile.empty())
396 llvm::report_fatal_error("--benchmarks-file must be set.");
397
Clement Courbet53d35d22018-06-05 10:56:19 +0000398 llvm::InitializeNativeTarget();
399 llvm::InitializeNativeTargetAsmPrinter();
Clement Courbet4273e1e2018-06-15 07:30:45 +0000400 llvm::InitializeNativeTargetDisassembler();
Clement Courbet37f0ca02018-05-15 12:08:00 +0000401 // Read benchmarks.
Clement Courbet53d35d22018-06-05 10:56:19 +0000402 const LLVMState State;
Clement Courbet37f0ca02018-05-15 12:08:00 +0000403 const std::vector<InstructionBenchmark> Points =
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000404 ExitOnErr(InstructionBenchmark::readYamls(State, BenchmarkFile));
Clement Courbet37f0ca02018-05-15 12:08:00 +0000405 llvm::outs() << "Parsed " << Points.size() << " benchmark points\n";
406 if (Points.empty()) {
407 llvm::errs() << "no benchmarks to analyze\n";
408 return;
409 }
410 // FIXME: Check that all points have the same triple/cpu.
411 // FIXME: Merge points from several runs (latency and uops).
412
Clement Courbet37f0ca02018-05-15 12:08:00 +0000413 std::string Error;
414 const auto *TheTarget =
415 llvm::TargetRegistry::lookupTarget(Points[0].LLVMTriple, Error);
416 if (!TheTarget) {
417 llvm::errs() << "unknown target '" << Points[0].LLVMTriple << "'\n";
418 return;
419 }
Guillaume Chatelet64165922018-06-11 09:18:01 +0000420 const auto Clustering = ExitOnErr(InstructionBenchmarkClustering::create(
Clement Courbet37f0ca02018-05-15 12:08:00 +0000421 Points, AnalysisNumPoints, AnalysisEpsilon));
Clement Courbet6d6c1a92018-05-16 08:47:21 +0000422
423 const Analysis Analyzer(*TheTarget, Clustering);
424
Clement Courbetcf210742018-05-17 13:41:28 +0000425 maybeRunAnalysis<Analysis::PrintClusters>(Analyzer, "analysis clusters",
426 AnalysisClustersOutputFile);
427 maybeRunAnalysis<Analysis::PrintSchedClassInconsistencies>(
428 Analyzer, "sched class consistency analysis",
429 AnalysisInconsistenciesOutputFile);
Clement Courbetac74acd2018-04-04 11:37:06 +0000430}
431
432} // namespace exegesis
433
434int main(int Argc, char **Argv) {
435 llvm::cl::ParseCommandLineOptions(Argc, Argv, "");
436
Guillaume Chatelet64165922018-06-11 09:18:01 +0000437 exegesis::ExitOnErr.setExitCodeMapper([](const llvm::Error &Err) {
438 if (Err.isA<llvm::StringError>())
439 return EXIT_SUCCESS;
440 return EXIT_FAILURE;
441 });
442
Clement Courbet4860b982018-06-26 08:49:30 +0000443 if (BenchmarkMode == exegesis::InstructionBenchmark::Unknown) {
Clement Courbet37f0ca02018-05-15 12:08:00 +0000444 exegesis::analysisMain();
445 } else {
446 exegesis::benchmarkMain();
Clement Courbetac74acd2018-04-04 11:37:06 +0000447 }
Clement Courbetac74acd2018-04-04 11:37:06 +0000448 return EXIT_SUCCESS;
449}