[llvm-exegesis] Add a Configuration object for Benchmark.
[llvm-core.git] / tools / llvm-exegesis / lib / BenchmarkRunner.cpp
blob4926637e6a6b1d1a47654db1ce81db9d766d404e
1 //===-- BenchmarkRunner.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 //===----------------------------------------------------------------------===//
10 #include <array>
11 #include <string>
13 #include "Assembler.h"
14 #include "BenchmarkRunner.h"
15 #include "MCInstrDescView.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/Twine.h"
19 #include "llvm/Support/FileSystem.h"
20 #include "llvm/Support/FormatVariadic.h"
21 #include "llvm/Support/MemoryBuffer.h"
22 #include "llvm/Support/Program.h"
24 namespace exegesis {
26 BenchmarkRunner::InstructionFilter::~InstructionFilter() = default;
27 BenchmarkRunner::BenchmarkRunner(const LLVMState &State)
28 : State(State), MCInstrInfo(State.getInstrInfo()),
29 MCRegisterInfo(State.getRegInfo()),
30 RATC(MCRegisterInfo,
31 getFunctionReservedRegs(*State.createTargetMachine())) {}
32 BenchmarkRunner::~BenchmarkRunner() = default;
34 InstructionBenchmark BenchmarkRunner::run(unsigned Opcode,
35 const InstructionFilter &Filter,
36 unsigned NumRepetitions) {
37 InstructionBenchmark InstrBenchmark;
39 InstrBenchmark.Key.OpcodeName = State.getInstrInfo().getName(Opcode);
40 InstrBenchmark.Mode = getMode();
41 InstrBenchmark.CpuName = State.getCpuName();
42 InstrBenchmark.LLVMTriple = State.getTriple();
43 InstrBenchmark.NumRepetitions = NumRepetitions;
45 // Ignore instructions that we cannot run.
46 if (State.getInstrInfo().get(Opcode).isPseudo()) {
47 InstrBenchmark.Error = "Unsupported opcode: isPseudo";
48 return InstrBenchmark;
50 if (llvm::Error E = Filter.shouldRun(State, Opcode)) {
51 InstrBenchmark.Error = llvm::toString(std::move(E));
52 return InstrBenchmark;
54 llvm::raw_string_ostream InfoStream(InstrBenchmark.Info);
55 llvm::Expected<BenchmarkConfiguration> ConfigurationOrError =
56 createConfiguration(RATC, Opcode, InfoStream);
57 if (llvm::Error E = ConfigurationOrError.takeError()) {
58 InstrBenchmark.Error = llvm::toString(std::move(E));
59 return InstrBenchmark;
61 BenchmarkConfiguration &Configuration = ConfigurationOrError.get();
62 const std::vector<llvm::MCInst> &Snippet = Configuration.Snippet;
63 if (Snippet.empty()) {
64 InstrBenchmark.Error = "Empty snippet";
65 return InstrBenchmark;
67 for (const auto &MCInst : Snippet) {
68 InstrBenchmark.Key.Instructions.push_back(MCInst);
70 InfoStream << "Snippet:\n";
71 for (const auto &MCInst : Snippet) {
72 DumpMCInst(MCRegisterInfo, MCInstrInfo, MCInst, InfoStream);
73 InfoStream << "\n";
76 std::vector<llvm::MCInst> Code;
77 for (int I = 0; I < InstrBenchmark.NumRepetitions; ++I)
78 Code.push_back(Snippet[I % Snippet.size()]);
80 auto ExpectedObjectPath = writeObjectFile(Code);
81 if (llvm::Error E = ExpectedObjectPath.takeError()) {
82 InstrBenchmark.Error = llvm::toString(std::move(E));
83 return InstrBenchmark;
86 // FIXME: Check if TargetMachine or ExecutionEngine can be reused instead of
87 // creating one everytime.
88 const ExecutableFunction EF(State.createTargetMachine(),
89 getObjectFromFile(*ExpectedObjectPath));
90 InstrBenchmark.Measurements = runMeasurements(EF, NumRepetitions);
92 return InstrBenchmark;
95 llvm::Expected<std::string>
96 BenchmarkRunner::writeObjectFile(llvm::ArrayRef<llvm::MCInst> Code) const {
97 int ResultFD = 0;
98 llvm::SmallString<256> ResultPath;
99 if (llvm::Error E = llvm::errorCodeToError(llvm::sys::fs::createTemporaryFile(
100 "snippet", "o", ResultFD, ResultPath)))
101 return std::move(E);
102 llvm::raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
103 assembleToStream(State.createTargetMachine(), Code, OFS);
104 llvm::outs() << "Check generated assembly with: /usr/bin/objdump -d "
105 << ResultPath << "\n";
106 return ResultPath.str();
109 } // namespace exegesis