[MIParser] Set RegClassOrRegBank during instruction parsing
[llvm-complete.git] / tools / llvm-exegesis / lib / BenchmarkRunner.cpp
blob452cebf0ce50b405a20263a2870d515a5f516ff0
1 //===-- BenchmarkRunner.cpp -------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include <array>
10 #include <string>
12 #include "Assembler.h"
13 #include "BenchmarkRunner.h"
14 #include "Error.h"
15 #include "MCInstrDescView.h"
16 #include "PerfHelper.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ADT/Twine.h"
20 #include "llvm/Support/CrashRecoveryContext.h"
21 #include "llvm/Support/FileSystem.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include "llvm/Support/Program.h"
25 namespace llvm {
26 namespace exegesis {
28 BenchmarkRunner::BenchmarkRunner(const LLVMState &State,
29 InstructionBenchmark::ModeE Mode)
30 : State(State), Mode(Mode), Scratch(std::make_unique<ScratchSpace>()) {}
32 BenchmarkRunner::~BenchmarkRunner() = default;
34 namespace {
35 class FunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
36 public:
37 FunctionExecutorImpl(const LLVMState &State,
38 object::OwningBinary<object::ObjectFile> Obj,
39 BenchmarkRunner::ScratchSpace *Scratch)
40 : Function(State.createTargetMachine(), std::move(Obj)),
41 Scratch(Scratch) {}
43 private:
44 Expected<int64_t> runAndMeasure(const char *Counters) const override {
45 // We sum counts when there are several counters for a single ProcRes
46 // (e.g. P23 on SandyBridge).
47 int64_t CounterValue = 0;
48 SmallVector<StringRef, 2> CounterNames;
49 StringRef(Counters).split(CounterNames, '+');
50 char *const ScratchPtr = Scratch->ptr();
51 for (auto &CounterName : CounterNames) {
52 CounterName = CounterName.trim();
53 pfm::PerfEvent PerfEvent(CounterName);
54 if (!PerfEvent.valid())
55 report_fatal_error(
56 Twine("invalid perf event '").concat(CounterName).concat("'"));
57 pfm::Counter Counter(PerfEvent);
58 Scratch->clear();
60 CrashRecoveryContext CRC;
61 CrashRecoveryContext::Enable();
62 const bool Crashed = !CRC.RunSafely([this, &Counter, ScratchPtr]() {
63 Counter.start();
64 this->Function(ScratchPtr);
65 Counter.stop();
66 });
67 CrashRecoveryContext::Disable();
68 // FIXME: Better diagnosis.
69 if (Crashed)
70 return make_error<Failure>("snippet crashed while running");
72 CounterValue += Counter.read();
74 return CounterValue;
77 const ExecutableFunction Function;
78 BenchmarkRunner::ScratchSpace *const Scratch;
80 } // namespace
82 InstructionBenchmark BenchmarkRunner::runConfiguration(
83 const BenchmarkCode &BC, unsigned NumRepetitions,
84 const SnippetRepetitor &Repetitor, bool DumpObjectToDisk) const {
85 InstructionBenchmark InstrBenchmark;
86 InstrBenchmark.Mode = Mode;
87 InstrBenchmark.CpuName = State.getTargetMachine().getTargetCPU();
88 InstrBenchmark.LLVMTriple =
89 State.getTargetMachine().getTargetTriple().normalize();
90 InstrBenchmark.NumRepetitions = NumRepetitions;
91 InstrBenchmark.Info = BC.Info;
93 const std::vector<MCInst> &Instructions = BC.Key.Instructions;
95 InstrBenchmark.Key = BC.Key;
97 // Assemble at least kMinInstructionsForSnippet instructions by repeating the
98 // snippet for debug/analysis. This is so that the user clearly understands
99 // that the inside instructions are repeated.
100 constexpr const int kMinInstructionsForSnippet = 16;
102 SmallString<0> Buffer;
103 raw_svector_ostream OS(Buffer);
104 assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
105 BC.LiveIns, BC.Key.RegisterInitialValues,
106 Repetitor.Repeat(Instructions, kMinInstructionsForSnippet),
107 OS);
108 const ExecutableFunction EF(State.createTargetMachine(),
109 getObjectFromBuffer(OS.str()));
110 const auto FnBytes = EF.getFunctionBytes();
111 InstrBenchmark.AssembledSnippet.assign(FnBytes.begin(), FnBytes.end());
114 // Assemble NumRepetitions instructions repetitions of the snippet for
115 // measurements.
116 const auto Filler =
117 Repetitor.Repeat(Instructions, InstrBenchmark.NumRepetitions);
119 object::OwningBinary<object::ObjectFile> ObjectFile;
120 if (DumpObjectToDisk) {
121 auto ObjectFilePath = writeObjectFile(BC, Filler);
122 if (Error E = ObjectFilePath.takeError()) {
123 InstrBenchmark.Error = toString(std::move(E));
124 return InstrBenchmark;
126 outs() << "Check generated assembly with: /usr/bin/objdump -d "
127 << *ObjectFilePath << "\n";
128 ObjectFile = getObjectFromFile(*ObjectFilePath);
129 } else {
130 SmallString<0> Buffer;
131 raw_svector_ostream OS(Buffer);
132 assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
133 BC.LiveIns, BC.Key.RegisterInitialValues, Filler, OS);
134 ObjectFile = getObjectFromBuffer(OS.str());
137 const FunctionExecutorImpl Executor(State, std::move(ObjectFile),
138 Scratch.get());
139 auto Measurements = runMeasurements(Executor);
140 if (Error E = Measurements.takeError()) {
141 InstrBenchmark.Error = toString(std::move(E));
142 return InstrBenchmark;
144 InstrBenchmark.Measurements = std::move(*Measurements);
145 assert(InstrBenchmark.NumRepetitions > 0 && "invalid NumRepetitions");
146 for (BenchmarkMeasure &BM : InstrBenchmark.Measurements) {
147 // Scale the measurements by instruction.
148 BM.PerInstructionValue /= InstrBenchmark.NumRepetitions;
149 // Scale the measurements by snippet.
150 BM.PerSnippetValue *= static_cast<double>(Instructions.size()) /
151 InstrBenchmark.NumRepetitions;
154 return InstrBenchmark;
157 Expected<std::string>
158 BenchmarkRunner::writeObjectFile(const BenchmarkCode &BC,
159 const FillFunction &FillFunction) const {
160 int ResultFD = 0;
161 SmallString<256> ResultPath;
162 if (Error E = errorCodeToError(
163 sys::fs::createTemporaryFile("snippet", "o", ResultFD, ResultPath)))
164 return std::move(E);
165 raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
166 assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
167 BC.LiveIns, BC.Key.RegisterInitialValues, FillFunction, OFS);
168 return ResultPath.str();
171 BenchmarkRunner::FunctionExecutor::~FunctionExecutor() {}
173 } // namespace exegesis
174 } // namespace llvm