[UpdateCCTestChecks] Detect function mangled name on separate line
[llvm-core.git] / tools / llvm-exegesis / lib / BenchmarkRunner.cpp
blobda26bc458dcf2aa895c841a3f8778bc4498054c1
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 llvm::object::OwningBinary<llvm::object::ObjectFile> Obj,
39 BenchmarkRunner::ScratchSpace *Scratch)
40 : Function(State.createTargetMachine(), std::move(Obj)),
41 Scratch(Scratch) {}
43 private:
44 llvm::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 llvm::SmallVector<llvm::StringRef, 2> CounterNames;
49 llvm::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 llvm::report_fatal_error(llvm::Twine("invalid perf event '")
56 .concat(CounterName)
57 .concat("'"));
58 pfm::Counter Counter(PerfEvent);
59 Scratch->clear();
61 llvm::CrashRecoveryContext CRC;
62 llvm::CrashRecoveryContext::Enable();
63 const bool Crashed = !CRC.RunSafely([this, &Counter, ScratchPtr]() {
64 Counter.start();
65 this->Function(ScratchPtr);
66 Counter.stop();
67 });
68 llvm::CrashRecoveryContext::Disable();
69 // FIXME: Better diagnosis.
70 if (Crashed)
71 return make_error<Failure>("snippet crashed while running");
73 CounterValue += Counter.read();
75 return CounterValue;
78 const ExecutableFunction Function;
79 BenchmarkRunner::ScratchSpace *const Scratch;
81 } // namespace
83 InstructionBenchmark BenchmarkRunner::runConfiguration(
84 const BenchmarkCode &BC, unsigned NumRepetitions,
85 const SnippetRepetitor &Repetitor, bool DumpObjectToDisk) const {
86 InstructionBenchmark InstrBenchmark;
87 InstrBenchmark.Mode = Mode;
88 InstrBenchmark.CpuName = State.getTargetMachine().getTargetCPU();
89 InstrBenchmark.LLVMTriple =
90 State.getTargetMachine().getTargetTriple().normalize();
91 InstrBenchmark.NumRepetitions = NumRepetitions;
92 InstrBenchmark.Info = BC.Info;
94 const std::vector<llvm::MCInst> &Instructions = BC.Key.Instructions;
96 InstrBenchmark.Key = BC.Key;
98 // Assemble at least kMinInstructionsForSnippet instructions by repeating the
99 // snippet for debug/analysis. This is so that the user clearly understands
100 // that the inside instructions are repeated.
101 constexpr const int kMinInstructionsForSnippet = 16;
103 llvm::SmallString<0> Buffer;
104 llvm::raw_svector_ostream OS(Buffer);
105 assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
106 BC.LiveIns, BC.Key.RegisterInitialValues,
107 Repetitor.Repeat(Instructions, kMinInstructionsForSnippet),
108 OS);
109 const ExecutableFunction EF(State.createTargetMachine(),
110 getObjectFromBuffer(OS.str()));
111 const auto FnBytes = EF.getFunctionBytes();
112 InstrBenchmark.AssembledSnippet.assign(FnBytes.begin(), FnBytes.end());
115 // Assemble NumRepetitions instructions repetitions of the snippet for
116 // measurements.
117 const auto Filler =
118 Repetitor.Repeat(Instructions, InstrBenchmark.NumRepetitions);
120 llvm::object::OwningBinary<llvm::object::ObjectFile> ObjectFile;
121 if (DumpObjectToDisk) {
122 auto ObjectFilePath = writeObjectFile(BC, Filler);
123 if (llvm::Error E = ObjectFilePath.takeError()) {
124 InstrBenchmark.Error = llvm::toString(std::move(E));
125 return InstrBenchmark;
127 llvm::outs() << "Check generated assembly with: /usr/bin/objdump -d "
128 << *ObjectFilePath << "\n";
129 ObjectFile = getObjectFromFile(*ObjectFilePath);
130 } else {
131 llvm::SmallString<0> Buffer;
132 llvm::raw_svector_ostream OS(Buffer);
133 assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
134 BC.LiveIns, BC.Key.RegisterInitialValues, Filler, OS);
135 ObjectFile = getObjectFromBuffer(OS.str());
138 const FunctionExecutorImpl Executor(State, std::move(ObjectFile),
139 Scratch.get());
140 auto Measurements = runMeasurements(Executor);
141 if (llvm::Error E = Measurements.takeError()) {
142 InstrBenchmark.Error = llvm::toString(std::move(E));
143 return InstrBenchmark;
145 InstrBenchmark.Measurements = std::move(*Measurements);
146 assert(InstrBenchmark.NumRepetitions > 0 && "invalid NumRepetitions");
147 for (BenchmarkMeasure &BM : InstrBenchmark.Measurements) {
148 // Scale the measurements by instruction.
149 BM.PerInstructionValue /= InstrBenchmark.NumRepetitions;
150 // Scale the measurements by snippet.
151 BM.PerSnippetValue *= static_cast<double>(Instructions.size()) /
152 InstrBenchmark.NumRepetitions;
155 return InstrBenchmark;
158 llvm::Expected<std::string>
159 BenchmarkRunner::writeObjectFile(const BenchmarkCode &BC,
160 const FillFunction &FillFunction) const {
161 int ResultFD = 0;
162 llvm::SmallString<256> ResultPath;
163 if (llvm::Error E = llvm::errorCodeToError(llvm::sys::fs::createTemporaryFile(
164 "snippet", "o", ResultFD, ResultPath)))
165 return std::move(E);
166 llvm::raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
167 assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
168 BC.LiveIns, BC.Key.RegisterInitialValues, FillFunction, OFS);
169 return ResultPath.str();
172 BenchmarkRunner::FunctionExecutor::~FunctionExecutor() {}
174 } // namespace exegesis
175 } // namespace llvm