1 | //===-- BenchmarkRunner.h ---------------------------------------*- 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 | //===----------------------------------------------------------------------===// |
8 | /// |
9 | /// \file |
10 | /// Defines the abstract BenchmarkRunner class for measuring a certain execution |
11 | /// property of instructions (e.g. latency). |
12 | /// |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #ifndef LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRUNNER_H |
16 | #define LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRUNNER_H |
17 | |
18 | #include "Assembler.h" |
19 | #include "BenchmarkCode.h" |
20 | #include "BenchmarkResult.h" |
21 | #include "LlvmState.h" |
22 | #include "MCInstrDescView.h" |
23 | #include "SnippetRepetitor.h" |
24 | #include "llvm/ADT/SmallVector.h" |
25 | #include "llvm/MC/MCInst.h" |
26 | #include "llvm/Support/Error.h" |
27 | #include <cstdlib> |
28 | #include <memory> |
29 | #include <vector> |
30 | |
31 | namespace llvm { |
32 | namespace exegesis { |
33 | |
34 | // Common code for all benchmark modes. |
35 | class BenchmarkRunner { |
36 | public: |
37 | enum ExecutionModeE { InProcess, SubProcess }; |
38 | |
39 | explicit BenchmarkRunner(const LLVMState &State, Benchmark::ModeE Mode, |
40 | BenchmarkPhaseSelectorE BenchmarkPhaseSelector, |
41 | ExecutionModeE ExecutionMode, |
42 | ArrayRef<ValidationEvent> ValCounters); |
43 | |
44 | virtual ~BenchmarkRunner(); |
45 | |
46 | class RunnableConfiguration { |
47 | friend class BenchmarkRunner; |
48 | |
49 | public: |
50 | ~RunnableConfiguration() = default; |
51 | RunnableConfiguration(RunnableConfiguration &&) = default; |
52 | |
53 | RunnableConfiguration(const RunnableConfiguration &) = delete; |
54 | RunnableConfiguration &operator=(RunnableConfiguration &&) = delete; |
55 | RunnableConfiguration &operator=(const RunnableConfiguration &) = delete; |
56 | |
57 | private: |
58 | RunnableConfiguration() = default; |
59 | |
60 | Benchmark BenchmarkResult; |
61 | object::OwningBinary<object::ObjectFile> ObjectFile; |
62 | }; |
63 | |
64 | Expected<RunnableConfiguration> |
65 | getRunnableConfiguration(const BenchmarkCode &Configuration, |
66 | unsigned MinInstructions, unsigned LoopUnrollFactor, |
67 | const SnippetRepetitor &Repetitor) const; |
68 | |
69 | std::pair<Error, Benchmark> |
70 | runConfiguration(RunnableConfiguration &&RC, |
71 | const std::optional<StringRef> &DumpFile, |
72 | std::optional<int> BenchmarkProcessCPU) const; |
73 | |
74 | // Scratch space to run instructions that touch memory. |
75 | struct ScratchSpace { |
76 | static constexpr const size_t kAlignment = 1024; |
77 | static constexpr const size_t kSize = 1 << 20; // 1MB. |
78 | ScratchSpace() |
79 | : UnalignedPtr(std::make_unique<char[]>(num: kSize + kAlignment)), |
80 | AlignedPtr( |
81 | UnalignedPtr.get() + kAlignment - |
82 | (reinterpret_cast<intptr_t>(UnalignedPtr.get()) % kAlignment)) {} |
83 | char *ptr() const { return AlignedPtr; } |
84 | void clear() { std::memset(s: ptr(), c: 0, n: kSize); } |
85 | |
86 | private: |
87 | const std::unique_ptr<char[]> UnalignedPtr; |
88 | char *const AlignedPtr; |
89 | }; |
90 | |
91 | // A helper to measure counters while executing a function in a sandboxed |
92 | // context. |
93 | class FunctionExecutor { |
94 | public: |
95 | virtual ~FunctionExecutor(); |
96 | |
97 | Expected<SmallVector<int64_t, 4>> |
98 | runAndSample(const char *Counters, |
99 | ArrayRef<const char *> ValidationCounters, |
100 | SmallVectorImpl<int64_t> &ValidationCounterValues) const; |
101 | |
102 | protected: |
103 | static void |
104 | accumulateCounterValues(const SmallVectorImpl<int64_t> &NewValues, |
105 | SmallVectorImpl<int64_t> *Result); |
106 | virtual Expected<SmallVector<int64_t, 4>> |
107 | runWithCounter(StringRef CounterName, |
108 | ArrayRef<const char *> ValidationCounters, |
109 | SmallVectorImpl<int64_t> &ValidationCounterValues) const = 0; |
110 | }; |
111 | |
112 | protected: |
113 | const LLVMState &State; |
114 | const Benchmark::ModeE Mode; |
115 | const BenchmarkPhaseSelectorE BenchmarkPhaseSelector; |
116 | const ExecutionModeE ExecutionMode; |
117 | |
118 | SmallVector<ValidationEvent> ValidationCounters; |
119 | |
120 | Error |
121 | getValidationCountersToRun(SmallVector<const char *> &ValCountersToRun) const; |
122 | |
123 | private: |
124 | virtual Expected<std::vector<BenchmarkMeasure>> |
125 | runMeasurements(const FunctionExecutor &Executor) const = 0; |
126 | |
127 | Expected<SmallString<0>> |
128 | assembleSnippet(const BenchmarkCode &BC, const SnippetRepetitor &Repetitor, |
129 | unsigned MinInstructions, unsigned LoopBodySize, |
130 | bool GenerateMemoryInstructions) const; |
131 | |
132 | Expected<std::string> writeObjectFile(StringRef Buffer, |
133 | StringRef FileName) const; |
134 | |
135 | const std::unique_ptr<ScratchSpace> Scratch; |
136 | |
137 | Expected<std::unique_ptr<FunctionExecutor>> |
138 | createFunctionExecutor(object::OwningBinary<object::ObjectFile> Obj, |
139 | const BenchmarkKey &Key, |
140 | std::optional<int> BenchmarkProcessCPU) const; |
141 | }; |
142 | |
143 | } // namespace exegesis |
144 | } // namespace llvm |
145 | |
146 | #endif // LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRUNNER_H |
147 | |