1 | //===-- BenchmarkResult.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 classes to represent measurements and serialize/deserialize them to |
11 | // Yaml. |
12 | /// |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #ifndef LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H |
16 | #define LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H |
17 | |
18 | #include "LlvmState.h" |
19 | #include "RegisterValue.h" |
20 | #include "ValidationEvent.h" |
21 | #include "llvm/ADT/StringRef.h" |
22 | #include "llvm/MC/MCInst.h" |
23 | #include "llvm/MC/MCInstBuilder.h" |
24 | #include "llvm/Support/YAMLTraits.h" |
25 | #include <limits> |
26 | #include <set> |
27 | #include <string> |
28 | #include <unordered_map> |
29 | #include <vector> |
30 | |
31 | namespace llvm { |
32 | class Error; |
33 | |
34 | namespace exegesis { |
35 | |
36 | enum class BenchmarkPhaseSelectorE { |
37 | PrepareSnippet, |
38 | PrepareAndAssembleSnippet, |
39 | AssembleMeasuredCode, |
40 | Measure, |
41 | }; |
42 | |
43 | enum class BenchmarkFilter { All, RegOnly, WithMem }; |
44 | |
45 | struct MemoryValue { |
46 | // The arbitrary bit width constant that defines the value. |
47 | APInt Value; |
48 | // The size of the value in bytes. |
49 | size_t SizeBytes; |
50 | // The index of the memory value. |
51 | size_t Index; |
52 | }; |
53 | |
54 | struct MemoryMapping { |
55 | // The address to place the mapping at. |
56 | intptr_t Address; |
57 | // The name of the value that should be mapped. |
58 | std::string MemoryValueName; |
59 | }; |
60 | |
61 | struct BenchmarkKey { |
62 | // The LLVM opcode name. |
63 | std::vector<MCInst> Instructions; |
64 | // The initial values of the registers. |
65 | std::vector<RegisterValue> RegisterInitialValues; |
66 | // The memory values that can be mapped into the execution context of the |
67 | // snippet. |
68 | std::unordered_map<std::string, MemoryValue> MemoryValues; |
69 | // The memory mappings that the snippet can access. |
70 | std::vector<MemoryMapping> MemoryMappings; |
71 | // An opaque configuration, that can be used to separate several benchmarks of |
72 | // the same instruction under different configurations. |
73 | std::string Config; |
74 | // The address that the snippet should be loaded in at if the execution mode |
75 | // being used supports it. |
76 | intptr_t SnippetAddress = 0; |
77 | // The register that should be used to hold the loop counter. |
78 | unsigned LoopRegister; |
79 | }; |
80 | |
81 | struct BenchmarkMeasure { |
82 | // A helper to create an unscaled BenchmarkMeasure. |
83 | static BenchmarkMeasure |
84 | Create(std::string Key, double Value, |
85 | std::map<ValidationEvent, int64_t> ValCounters) { |
86 | return {.Key: Key, .PerInstructionValue: Value, .PerSnippetValue: Value, .RawValue: Value, .ValidationCounters: ValCounters}; |
87 | } |
88 | std::string Key; |
89 | // This is the per-instruction value, i.e. measured quantity scaled per |
90 | // instruction. |
91 | double PerInstructionValue; |
92 | // This is the per-snippet value, i.e. measured quantity for one repetition of |
93 | // the whole snippet. |
94 | double PerSnippetValue; |
95 | // This is the raw value collected from the full execution. |
96 | double RawValue; |
97 | // These are the validation counter values. |
98 | std::map<ValidationEvent, int64_t> ValidationCounters; |
99 | }; |
100 | |
101 | // The result of an instruction benchmark. |
102 | struct Benchmark { |
103 | BenchmarkKey Key; |
104 | enum ModeE { Unknown, Latency, Uops, InverseThroughput }; |
105 | ModeE Mode; |
106 | std::string CpuName; |
107 | std::string LLVMTriple; |
108 | // Which instruction is being benchmarked here? |
109 | const MCInst &keyInstruction() const { return Key.Instructions[0]; } |
110 | // The number of instructions inside the repeated snippet. For example, if a |
111 | // snippet of 3 instructions is repeated 4 times, this is 12. |
112 | unsigned MinInstructions = 0; |
113 | enum RepetitionModeE { |
114 | Duplicate, |
115 | Loop, |
116 | AggregateMin, |
117 | MiddleHalfDuplicate, |
118 | MiddleHalfLoop |
119 | }; |
120 | // Note that measurements are per instruction. |
121 | std::vector<BenchmarkMeasure> Measurements; |
122 | std::string Error; |
123 | std::string Info; |
124 | std::vector<uint8_t> AssembledSnippet; |
125 | // How to aggregate measurements. |
126 | enum ResultAggregationModeE { Min, Max, Mean, MinVariance }; |
127 | |
128 | Benchmark() = default; |
129 | Benchmark(Benchmark &&) = default; |
130 | |
131 | Benchmark(const Benchmark &) = delete; |
132 | Benchmark &operator=(const Benchmark &) = delete; |
133 | Benchmark &operator=(Benchmark &&) = delete; |
134 | |
135 | // Read functions. |
136 | static Expected<Benchmark> readYaml(const LLVMState &State, |
137 | MemoryBufferRef Buffer); |
138 | |
139 | static Expected<std::vector<Benchmark>> |
140 | readYamls(const LLVMState &State, MemoryBufferRef Buffer); |
141 | |
142 | // Given a set of serialized instruction benchmarks, returns the set of |
143 | // triples and CPUs that appear in the list of benchmarks. |
144 | struct TripleAndCpu { |
145 | std::string LLVMTriple; |
146 | std::string CpuName; |
147 | bool operator<(const TripleAndCpu &O) const { |
148 | return std::tie(args: LLVMTriple, args: CpuName) < std::tie(args: O.LLVMTriple, args: O.CpuName); |
149 | } |
150 | }; |
151 | static Expected<std::set<TripleAndCpu>> |
152 | readTriplesAndCpusFromYamls(MemoryBufferRef Buffer); |
153 | |
154 | class Error readYamlFrom(const LLVMState &State, StringRef InputContent); |
155 | |
156 | // Write functions, non-const because of YAML traits. |
157 | // NOTE: we intentionally do *NOT* have a variant of this function taking |
158 | // filename, because it's behaviour is bugprone with regards to |
159 | // accidentally using it more than once and overriding previous YAML. |
160 | class Error writeYamlTo(const LLVMState &State, raw_ostream &S); |
161 | }; |
162 | |
163 | bool operator==(const BenchmarkMeasure &A, const BenchmarkMeasure &B); |
164 | |
165 | //------------------------------------------------------------------------------ |
166 | // Utilities to work with Benchmark measures. |
167 | |
168 | // A class that measures stats over benchmark measures. |
169 | class PerInstructionStats { |
170 | public: |
171 | void push(const BenchmarkMeasure &BM); |
172 | |
173 | double avg() const { |
174 | assert(NumValues); |
175 | return SumValues / NumValues; |
176 | } |
177 | double min() const { return MinValue; } |
178 | double max() const { return MaxValue; } |
179 | |
180 | const std::string &key() const { return Key; } |
181 | |
182 | private: |
183 | std::string Key; |
184 | double SumValues = 0.0; |
185 | int NumValues = 0; |
186 | double MaxValue = std::numeric_limits<double>::min(); |
187 | double MinValue = std::numeric_limits<double>::max(); |
188 | }; |
189 | |
190 | } // namespace exegesis |
191 | } // namespace llvm |
192 | |
193 | #endif // LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H |
194 | |