blob: f9ecbae060dee163d3afa46f4f1b1c4d35f177e4 [file] [log] [blame]
Clement Courbetac74acd2018-04-04 11:37:06 +00001//===-- 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//===----------------------------------------------------------------------===//
9
Clement Courbet0e69e2d2018-05-17 10:52:18 +000010#include <array>
11#include <string>
12
13#include "Assembler.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000014#include "BenchmarkRunner.h"
Clement Courbet0e69e2d2018-05-17 10:52:18 +000015#include "MCInstrDescView.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000016#include "llvm/ADT/StringExtras.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/ADT/Twine.h"
Clement Courbet0e69e2d2018-05-17 10:52:18 +000019#include "llvm/Support/FileSystem.h"
20#include "llvm/Support/FormatVariadic.h"
21#include "llvm/Support/MemoryBuffer.h"
22#include "llvm/Support/Program.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000023
24namespace exegesis {
25
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000026BenchmarkFailure::BenchmarkFailure(const llvm::Twine &S)
27 : llvm::StringError(S, llvm::inconvertibleErrorCode()) {}
28
Clement Courbetac74acd2018-04-04 11:37:06 +000029BenchmarkRunner::InstructionFilter::~InstructionFilter() = default;
Guillaume Chateletb4f15822018-06-07 14:00:29 +000030
Clement Courbet0e69e2d2018-05-17 10:52:18 +000031BenchmarkRunner::BenchmarkRunner(const LLVMState &State)
32 : State(State), MCInstrInfo(State.getInstrInfo()),
33 MCRegisterInfo(State.getRegInfo()),
34 RATC(MCRegisterInfo,
35 getFunctionReservedRegs(*State.createTargetMachine())) {}
Guillaume Chateletb4f15822018-06-07 14:00:29 +000036
Clement Courbetac74acd2018-04-04 11:37:06 +000037BenchmarkRunner::~BenchmarkRunner() = default;
38
Guillaume Chateletb4f15822018-06-07 14:00:29 +000039llvm::Expected<std::vector<InstructionBenchmark>>
40BenchmarkRunner::run(unsigned Opcode, const InstructionFilter &Filter,
41 unsigned NumRepetitions) {
42 // Ignore instructions that we cannot run.
43 if (State.getInstrInfo().get(Opcode).isPseudo())
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000044 return llvm::make_error<BenchmarkFailure>("Unsupported opcode: isPseudo");
Clement Courbetac74acd2018-04-04 11:37:06 +000045
Guillaume Chateletb4f15822018-06-07 14:00:29 +000046 if (llvm::Error E = Filter.shouldRun(State, Opcode))
47 return std::move(E);
48
49 llvm::Expected<std::vector<BenchmarkConfiguration>> ConfigurationOrError =
Guillaume Chateletef6cef52018-06-20 08:52:30 +000050 generateConfigurations(Opcode);
Guillaume Chateletb4f15822018-06-07 14:00:29 +000051
52 if (llvm::Error E = ConfigurationOrError.takeError())
53 return std::move(E);
54
55 std::vector<InstructionBenchmark> InstrBenchmarks;
56 for (const BenchmarkConfiguration &Conf : ConfigurationOrError.get())
57 InstrBenchmarks.push_back(runOne(Conf, Opcode, NumRepetitions));
58 return InstrBenchmarks;
59}
60
61InstructionBenchmark
62BenchmarkRunner::runOne(const BenchmarkConfiguration &Configuration,
63 unsigned Opcode, unsigned NumRepetitions) const {
64 InstructionBenchmark InstrBenchmark;
Clement Courbet62b34fa2018-06-06 09:42:36 +000065 InstrBenchmark.Mode = getMode();
Clement Courbet760d1d52018-06-21 14:11:09 +000066 InstrBenchmark.CpuName = State.getTargetMachine().getTargetCPU();
67 InstrBenchmark.LLVMTriple =
68 State.getTargetMachine().getTargetTriple().normalize();
Clement Courbetac74acd2018-04-04 11:37:06 +000069 InstrBenchmark.NumRepetitions = NumRepetitions;
Guillaume Chateletb4f15822018-06-07 14:00:29 +000070 InstrBenchmark.Info = Configuration.Info;
Clement Courbetac74acd2018-04-04 11:37:06 +000071
Guillaume Chatelet7b852cd2018-06-07 08:11:54 +000072 const std::vector<llvm::MCInst> &Snippet = Configuration.Snippet;
Clement Courbet0e69e2d2018-05-17 10:52:18 +000073 if (Snippet.empty()) {
74 InstrBenchmark.Error = "Empty snippet";
75 return InstrBenchmark;
76 }
Guillaume Chateletb4f15822018-06-07 14:00:29 +000077
Clement Courbet4273e1e2018-06-15 07:30:45 +000078 InstrBenchmark.Key.Instructions = Snippet;
Clement Courbet0e69e2d2018-05-17 10:52:18 +000079
Clement Courbet4273e1e2018-06-15 07:30:45 +000080 // Repeat the snippet until there are at least NumInstructions in the
81 // resulting code. The snippet is always repeated at least once.
82 const auto GenerateInstructions = [&Snippet](const int MinInstructions) {
83 std::vector<llvm::MCInst> Code = Snippet;
84 for (int I = 0; I < MinInstructions; ++I)
85 Code.push_back(Snippet[I % Snippet.size()]);
86 return Code;
87 };
Clement Courbet0e69e2d2018-05-17 10:52:18 +000088
Clement Courbet4273e1e2018-06-15 07:30:45 +000089 // Assemble at least kMinInstructionsForSnippet instructions by repeating the
90 // snippet for debug/analysis. This is so that the user clearly understands
91 // that the inside instructions are repeated.
92 constexpr const int kMinInstructionsForSnippet = 16;
93 {
Clement Courbet1ef6aa82018-06-21 14:49:04 +000094 auto ObjectFilePath = writeObjectFile(
Clement Courbet4273e1e2018-06-15 07:30:45 +000095 GenerateInstructions(kMinInstructionsForSnippet));
Clement Courbet1ef6aa82018-06-21 14:49:04 +000096 if (llvm::Error E = ObjectFilePath.takeError()) {
Clement Courbet4273e1e2018-06-15 07:30:45 +000097 InstrBenchmark.Error = llvm::toString(std::move(E));
98 return InstrBenchmark;
99 }
Clement Courbet1ef6aa82018-06-21 14:49:04 +0000100 const ExecutableFunction EF(State.createTargetMachine(),
101 getObjectFromFile(*ObjectFilePath));
102 const auto FnBytes = EF.getFunctionBytes();
Clement Courbet4273e1e2018-06-15 07:30:45 +0000103 InstrBenchmark.AssembledSnippet.assign(FnBytes.begin(), FnBytes.end());
104 }
105
106 // Assemble NumRepetitions instructions repetitions of the snippet for
107 // measurements.
Clement Courbet1ef6aa82018-06-21 14:49:04 +0000108 auto ObjectFilePath = writeObjectFile(
Clement Courbet4273e1e2018-06-15 07:30:45 +0000109 GenerateInstructions(InstrBenchmark.NumRepetitions));
Clement Courbet1ef6aa82018-06-21 14:49:04 +0000110 if (llvm::Error E = ObjectFilePath.takeError()) {
Clement Courbetac74acd2018-04-04 11:37:06 +0000111 InstrBenchmark.Error = llvm::toString(std::move(E));
112 return InstrBenchmark;
113 }
Clement Courbet1ef6aa82018-06-21 14:49:04 +0000114 llvm::outs() << "Check generated assembly with: /usr/bin/objdump -d "
115 << *ObjectFilePath << "\n";
116 const ExecutableFunction EF(State.createTargetMachine(),
117 getObjectFromFile(*ObjectFilePath));
118 InstrBenchmark.Measurements = runMeasurements(EF, NumRepetitions);
Clement Courbetac74acd2018-04-04 11:37:06 +0000119
Clement Courbetac74acd2018-04-04 11:37:06 +0000120 return InstrBenchmark;
121}
122
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000123llvm::Expected<std::vector<BenchmarkConfiguration>>
124BenchmarkRunner::generateConfigurations(unsigned Opcode) const {
125 if (auto E = generatePrototype(Opcode)) {
126 SnippetPrototype &Prototype = E.get();
127 // TODO: Generate as many configurations as needed here.
128 BenchmarkConfiguration Configuration;
129 Configuration.Info = Prototype.Explanation;
130 for (InstructionInstance &II : Prototype.Snippet)
131 Configuration.Snippet.push_back(II.randomizeUnsetVariablesAndBuild());
132 return std::vector<BenchmarkConfiguration>{Configuration};
133 } else
134 return E.takeError();
135}
136
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000137llvm::Expected<std::string>
138BenchmarkRunner::writeObjectFile(llvm::ArrayRef<llvm::MCInst> Code) const {
139 int ResultFD = 0;
140 llvm::SmallString<256> ResultPath;
141 if (llvm::Error E = llvm::errorCodeToError(llvm::sys::fs::createTemporaryFile(
142 "snippet", "o", ResultFD, ResultPath)))
143 return std::move(E);
144 llvm::raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
145 assembleToStream(State.createTargetMachine(), Code, OFS);
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000146 return ResultPath.str();
147}
148
Clement Courbetac74acd2018-04-04 11:37:06 +0000149} // namespace exegesis