1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
//===-- BenchmarkResult.h ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Defines classes to represent measurements and serialize/deserialize them to
// Yaml.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H
#define LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/Support/YAMLTraits.h"
#include <limits>
#include <string>
#include <unordered_map>
#include <vector>
namespace exegesis {
struct BenchmarkResultContext; // Forward declaration.
struct InstructionBenchmarkKey {
// The LLVM opcode name.
std::vector<llvm::MCInst> Instructions;
// An opaque configuration, that can be used to separate several benchmarks of
// the same instruction under different configurations.
std::string Config;
};
struct BenchmarkMeasure {
std::string Key;
double Value;
std::string DebugString;
};
// The result of an instruction benchmark.
struct InstructionBenchmark {
InstructionBenchmarkKey Key;
enum ModeE { Unknown, Latency, Uops };
ModeE Mode;
std::string CpuName;
std::string LLVMTriple;
// The number of instructions inside the repeated snippet. For example, if a
// snippet of 3 instructions is repeated 4 times, this is 12.
int NumRepetitions = 0;
// Note that measurements are per instruction.
std::vector<BenchmarkMeasure> Measurements;
std::string Error;
std::string Info;
std::vector<uint8_t> AssembledSnippet;
// Read functions.
static llvm::Expected<InstructionBenchmark>
readYaml(const BenchmarkResultContext &Context, llvm::StringRef Filename);
static llvm::Expected<std::vector<InstructionBenchmark>>
readYamls(const BenchmarkResultContext &Context, llvm::StringRef Filename);
void readYamlFrom(const BenchmarkResultContext &Context,
llvm::StringRef InputContent);
// Write functions, non-const because of YAML traits.
void writeYamlTo(const BenchmarkResultContext &Context, llvm::raw_ostream &S);
llvm::Error writeYaml(const BenchmarkResultContext &Context,
const llvm::StringRef Filename);
};
//------------------------------------------------------------------------------
// Utilities to work with Benchmark measures.
// A class that measures stats over benchmark measures.
class BenchmarkMeasureStats {
public:
void push(const BenchmarkMeasure &BM);
double avg() const {
assert(NumValues);
return SumValues / NumValues;
}
double min() const { return MinValue; }
double max() const { return MaxValue; }
const std::string &key() const { return Key; }
private:
std::string Key;
double SumValues = 0.0;
int NumValues = 0;
double MaxValue = std::numeric_limits<double>::min();
double MinValue = std::numeric_limits<double>::max();
};
// This context is used when de/serializing InstructionBenchmark to guarantee
// that Registers and Instructions are human readable and preserved accross
// different versions of LLVM.
struct BenchmarkResultContext {
BenchmarkResultContext() = default;
BenchmarkResultContext(BenchmarkResultContext &&) = default;
BenchmarkResultContext &operator=(BenchmarkResultContext &&) = default;
BenchmarkResultContext(const BenchmarkResultContext &) = delete;
BenchmarkResultContext &operator=(const BenchmarkResultContext &) = delete;
// Populate Registers and Instruction mapping.
void addRegEntry(unsigned RegNo, llvm::StringRef Name);
void addInstrEntry(unsigned Opcode, llvm::StringRef Name);
// Register accessors.
llvm::StringRef getRegName(unsigned RegNo) const;
unsigned getRegNo(llvm::StringRef Name) const; // 0 is not found.
// Instruction accessors.
llvm::StringRef getInstrName(unsigned Opcode) const;
unsigned getInstrOpcode(llvm::StringRef Name) const; // 0 is not found.
private:
// Ideally we would like to use MCRegisterInfo and MCInstrInfo but doing so
// would make testing harder, instead we create a mapping that we can easily
// populate.
std::unordered_map<unsigned, llvm::StringRef> InstrOpcodeToName;
std::unordered_map<unsigned, llvm::StringRef> RegNoToName;
llvm::StringMap<unsigned> InstrNameToOpcode;
llvm::StringMap<unsigned> RegNameToNo;
};
} // namespace exegesis
#endif // LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H
|