194 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// Defines classes to represent measurements and serialize/deserialize them to11// Yaml.12///13//===----------------------------------------------------------------------===//14 15#ifndef LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H16#define LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H17 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 31namespace llvm {32class Error;33 34namespace exegesis {35 36enum class BenchmarkPhaseSelectorE {37 PrepareSnippet,38 PrepareAndAssembleSnippet,39 AssembleMeasuredCode,40 Measure,41};42 43enum class BenchmarkFilter { All, RegOnly, WithMem };44 45struct 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 54struct MemoryMapping {55 // The address to place the mapping at.56 uintptr_t Address;57 // The name of the value that should be mapped.58 std::string MemoryValueName;59};60 61struct 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 the67 // 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 of72 // the same instruction under different configurations.73 std::string Config;74 // The address that the snippet should be loaded in at if the execution mode75 // being used supports it.76 uintptr_t SnippetAddress = 0;77 // The register that should be used to hold the loop counter.78 MCRegister LoopRegister;79};80 81struct BenchmarkMeasure {82 // A helper to create an unscaled BenchmarkMeasure.83 static BenchmarkMeasure84 Create(std::string Key, double Value,85 std::map<ValidationEvent, int64_t> ValCounters) {86 return {Key, Value, Value, Value, ValCounters};87 }88 std::string Key;89 // This is the per-instruction value, i.e. measured quantity scaled per90 // instruction.91 double PerInstructionValue;92 // This is the per-snippet value, i.e. measured quantity for one repetition of93 // 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.102struct 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 a111 // 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 MiddleHalfLoop119 };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 of143 // 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(LLVMTriple, CpuName) < std::tie(O.LLVMTriple, 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 taking158 // filename, because it's behaviour is bugprone with regards to159 // accidentally using it more than once and overriding previous YAML.160 class Error writeYamlTo(const LLVMState &State, raw_ostream &S);161};162 163bool 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.169class PerInstructionStats {170public: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 182private: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 exegesis191} // namespace llvm192 193#endif // LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H194