blob: 33ad65075d92d475ab71f82628bc63eb603c4aa9 [file] [log] [blame]
Clement Courbetac74acd2018-04-04 11:37:06 +00001//===-- BenchmarkResult.cpp -------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "BenchmarkResult.h"
Clement Courbet53d35d22018-06-05 10:56:19 +000011#include "llvm/ADT/STLExtras.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000012#include "llvm/ADT/StringRef.h"
Clement Courbet4273e1e2018-06-15 07:30:45 +000013#include "llvm/ObjectYAML/YAML.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000014#include "llvm/Support/FileOutputBuffer.h"
15#include "llvm/Support/FileSystem.h"
16#include "llvm/Support/Format.h"
17#include "llvm/Support/raw_ostream.h"
18
Guillaume Chatelet083a0c162018-06-07 07:40:40 +000019static constexpr const char kIntegerFormat[] = "i_0x%" PRId64 "x";
20static constexpr const char kDoubleFormat[] = "f_%la";
21
22static void serialize(const exegesis::BenchmarkResultContext &Context,
23 const llvm::MCOperand &MCOperand, llvm::raw_ostream &OS) {
24 if (MCOperand.isReg()) {
25 OS << Context.getRegName(MCOperand.getReg());
26 } else if (MCOperand.isImm()) {
27 OS << llvm::format(kIntegerFormat, MCOperand.getImm());
28 } else if (MCOperand.isFPImm()) {
29 OS << llvm::format(kDoubleFormat, MCOperand.getFPImm());
30 } else {
31 OS << "INVALID";
32 }
33}
34
35static void serialize(const exegesis::BenchmarkResultContext &Context,
36 const llvm::MCInst &MCInst, llvm::raw_ostream &OS) {
37 OS << Context.getInstrName(MCInst.getOpcode());
38 for (const auto &Op : MCInst) {
39 OS << ' ';
40 serialize(Context, Op, OS);
41 }
42}
43
44static llvm::MCOperand
45deserialize(const exegesis::BenchmarkResultContext &Context,
46 llvm::StringRef String) {
47 assert(!String.empty());
48 int64_t IntValue = 0;
49 double DoubleValue = 0;
50 if (sscanf(String.data(), kIntegerFormat, &IntValue) == 1)
51 return llvm::MCOperand::createImm(IntValue);
52 if (sscanf(String.data(), kDoubleFormat, &DoubleValue) == 1)
53 return llvm::MCOperand::createFPImm(DoubleValue);
54 if (unsigned RegNo = Context.getRegNo(String)) // Returns 0 if invalid.
55 return llvm::MCOperand::createReg(RegNo);
56 return {};
57}
58
59static llvm::StringRef
60deserialize(const exegesis::BenchmarkResultContext &Context,
61 llvm::StringRef String, llvm::MCInst &Value) {
62 llvm::SmallVector<llvm::StringRef, 8> Pieces;
63 String.split(Pieces, " ");
64 if (Pieces.empty())
65 return "Invalid Instruction";
66 bool ProcessOpcode = true;
67 for (llvm::StringRef Piece : Pieces) {
68 if (ProcessOpcode) {
69 ProcessOpcode = false;
70 Value.setOpcode(Context.getInstrOpcode(Piece));
71 if (Value.getOpcode() == 0)
72 return "Unknown Opcode Name";
73 } else {
74 Value.addOperand(deserialize(Context, Piece));
75 }
76 }
77 return {};
78}
79
80// YAML IO requires a mutable pointer to Context but we guarantee to not
81// modify it.
82static void *getUntypedContext(const exegesis::BenchmarkResultContext &Ctx) {
83 return const_cast<exegesis::BenchmarkResultContext *>(&Ctx);
84}
85
86static const exegesis::BenchmarkResultContext &getTypedContext(void *Ctx) {
87 assert(Ctx);
88 return *static_cast<const exegesis::BenchmarkResultContext *>(Ctx);
89}
90
Clement Courbetac74acd2018-04-04 11:37:06 +000091// Defining YAML traits for IO.
92namespace llvm {
93namespace yaml {
94
Clement Courbet53d35d22018-06-05 10:56:19 +000095// std::vector<llvm::MCInst> will be rendered as a list.
96template <> struct SequenceElementTraits<llvm::MCInst> {
97 static const bool flow = false;
98};
99
100template <> struct ScalarTraits<llvm::MCInst> {
101
102 static void output(const llvm::MCInst &Value, void *Ctx,
103 llvm::raw_ostream &Out) {
Guillaume Chatelet083a0c162018-06-07 07:40:40 +0000104 serialize(getTypedContext(Ctx), Value, Out);
Clement Courbet53d35d22018-06-05 10:56:19 +0000105 }
106
107 static StringRef input(StringRef Scalar, void *Ctx, llvm::MCInst &Value) {
Guillaume Chatelet083a0c162018-06-07 07:40:40 +0000108 return deserialize(getTypedContext(Ctx), Scalar, Value);
Clement Courbet53d35d22018-06-05 10:56:19 +0000109 }
110
111 static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
112
113 static const bool flow = true;
114};
115
Clement Courbetac74acd2018-04-04 11:37:06 +0000116// std::vector<exegesis::Measure> will be rendered as a list.
117template <> struct SequenceElementTraits<exegesis::BenchmarkMeasure> {
118 static const bool flow = false;
119};
120
121// exegesis::Measure is rendererd as a flow instead of a list.
122// e.g. { "key": "the key", "value": 0123 }
123template <> struct MappingTraits<exegesis::BenchmarkMeasure> {
124 static void mapping(IO &Io, exegesis::BenchmarkMeasure &Obj) {
125 Io.mapRequired("key", Obj.Key);
126 Io.mapRequired("value", Obj.Value);
127 Io.mapOptional("debug_string", Obj.DebugString);
128 }
129 static const bool flow = true;
130};
131
Clement Courbet2cb97b92018-06-04 11:43:40 +0000132template <>
Clement Courbet62b34fa2018-06-06 09:42:36 +0000133struct ScalarEnumerationTraits<exegesis::InstructionBenchmark::ModeE> {
Clement Courbet2cb97b92018-06-04 11:43:40 +0000134 static void enumeration(IO &Io,
Clement Courbet62b34fa2018-06-06 09:42:36 +0000135 exegesis::InstructionBenchmark::ModeE &Value) {
136 Io.enumCase(Value, "", exegesis::InstructionBenchmark::Unknown);
137 Io.enumCase(Value, "latency", exegesis::InstructionBenchmark::Latency);
138 Io.enumCase(Value, "uops", exegesis::InstructionBenchmark::Uops);
Clement Courbet2cb97b92018-06-04 11:43:40 +0000139 }
140};
141
Clement Courbeta66bfaa42018-05-15 13:07:05 +0000142template <> struct MappingTraits<exegesis::InstructionBenchmarkKey> {
143 static void mapping(IO &Io, exegesis::InstructionBenchmarkKey &Obj) {
Clement Courbet49fad1c2018-06-14 06:57:52 +0000144 Io.mapRequired("instructions", Obj.Instructions);
Clement Courbeta66bfaa42018-05-15 13:07:05 +0000145 Io.mapOptional("config", Obj.Config);
Clement Courbetac74acd2018-04-04 11:37:06 +0000146 }
147};
148
149template <> struct MappingTraits<exegesis::InstructionBenchmark> {
Clement Courbet4273e1e2018-06-15 07:30:45 +0000150 class NormalizedBinary {
151 public:
152 NormalizedBinary(IO &io) {}
153 NormalizedBinary(IO &, std::vector<uint8_t> &Data) : Binary(Data) {}
154 std::vector<uint8_t> denormalize(IO &) {
155 std::vector<uint8_t> Data;
156 std::string Str;
157 raw_string_ostream OSS(Str);
158 Binary.writeAsBinary(OSS);
159 OSS.flush();
160 Data.assign(Str.begin(), Str.end());
161 return Data;
162 }
163
164 BinaryRef Binary;
165 };
166
Clement Courbetac74acd2018-04-04 11:37:06 +0000167 static void mapping(IO &Io, exegesis::InstructionBenchmark &Obj) {
Clement Courbet62b34fa2018-06-06 09:42:36 +0000168 Io.mapRequired("mode", Obj.Mode);
Clement Courbeta66bfaa42018-05-15 13:07:05 +0000169 Io.mapRequired("key", Obj.Key);
Clement Courbetac74acd2018-04-04 11:37:06 +0000170 Io.mapRequired("cpu_name", Obj.CpuName);
171 Io.mapRequired("llvm_triple", Obj.LLVMTriple);
172 Io.mapRequired("num_repetitions", Obj.NumRepetitions);
173 Io.mapRequired("measurements", Obj.Measurements);
174 Io.mapRequired("error", Obj.Error);
Clement Courbeta66bfaa42018-05-15 13:07:05 +0000175 Io.mapOptional("info", Obj.Info);
Clement Courbet4273e1e2018-06-15 07:30:45 +0000176 // AssembledSnippet
177 MappingNormalization<NormalizedBinary, std::vector<uint8_t>> BinaryString(
178 Io, Obj.AssembledSnippet);
179 Io.mapOptional("assembled_snippet", BinaryString->Binary);
Clement Courbetac74acd2018-04-04 11:37:06 +0000180 }
181};
182
183} // namespace yaml
184} // namespace llvm
185
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000186LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(exegesis::InstructionBenchmark)
187
Clement Courbetac74acd2018-04-04 11:37:06 +0000188namespace exegesis {
189
Clement Courbet53d35d22018-06-05 10:56:19 +0000190void BenchmarkResultContext::addRegEntry(unsigned RegNo, llvm::StringRef Name) {
191 assert(RegNoToName.find(RegNo) == RegNoToName.end());
192 assert(RegNameToNo.find(Name) == RegNameToNo.end());
193 RegNoToName[RegNo] = Name;
194 RegNameToNo[Name] = RegNo;
195}
196
197llvm::StringRef BenchmarkResultContext::getRegName(unsigned RegNo) const {
198 const auto Itr = RegNoToName.find(RegNo);
199 if (Itr != RegNoToName.end())
200 return Itr->second;
201 return {};
202}
203
204unsigned BenchmarkResultContext::getRegNo(llvm::StringRef Name) const {
205 const auto Itr = RegNameToNo.find(Name);
206 if (Itr != RegNameToNo.end())
207 return Itr->second;
208 return 0;
209}
210
211void BenchmarkResultContext::addInstrEntry(unsigned Opcode,
212 llvm::StringRef Name) {
213 assert(InstrOpcodeToName.find(Opcode) == InstrOpcodeToName.end());
214 assert(InstrNameToOpcode.find(Name) == InstrNameToOpcode.end());
215 InstrOpcodeToName[Opcode] = Name;
216 InstrNameToOpcode[Name] = Opcode;
217}
218
219llvm::StringRef BenchmarkResultContext::getInstrName(unsigned Opcode) const {
220 const auto Itr = InstrOpcodeToName.find(Opcode);
221 if (Itr != InstrOpcodeToName.end())
222 return Itr->second;
223 return {};
224}
225
226unsigned BenchmarkResultContext::getInstrOpcode(llvm::StringRef Name) const {
227 const auto Itr = InstrNameToOpcode.find(Name);
228 if (Itr != InstrNameToOpcode.end())
229 return Itr->second;
230 return 0;
231}
232
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000233template <typename ObjectOrList>
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000234static llvm::Expected<ObjectOrList>
235readYamlCommon(const BenchmarkResultContext &Context,
236 llvm::StringRef Filename) {
237 if (auto ExpectedMemoryBuffer =
238 llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename))) {
239 std::unique_ptr<llvm::MemoryBuffer> MemoryBuffer =
240 std::move(ExpectedMemoryBuffer.get());
241 llvm::yaml::Input Yin(*MemoryBuffer, getUntypedContext(Context));
242 ObjectOrList Benchmark;
243 Yin >> Benchmark;
244 return Benchmark;
245 } else {
246 return ExpectedMemoryBuffer.takeError();
247 }
Clement Courbetac74acd2018-04-04 11:37:06 +0000248}
249
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000250llvm::Expected<InstructionBenchmark>
251InstructionBenchmark::readYaml(const BenchmarkResultContext &Context,
252 llvm::StringRef Filename) {
253 return readYamlCommon<InstructionBenchmark>(Context, Filename);
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000254}
255
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000256llvm::Expected<std::vector<InstructionBenchmark>>
257InstructionBenchmark::readYamls(const BenchmarkResultContext &Context,
258 llvm::StringRef Filename) {
259 return readYamlCommon<std::vector<InstructionBenchmark>>(Context, Filename);
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000260}
261
Clement Courbet53d35d22018-06-05 10:56:19 +0000262void InstructionBenchmark::writeYamlTo(const BenchmarkResultContext &Context,
Guillaume Chatelet083a0c162018-06-07 07:40:40 +0000263 llvm::raw_ostream &OS) {
264 llvm::yaml::Output Yout(OS, getUntypedContext(Context));
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000265 Yout << *this;
266}
267
Clement Courbet53d35d22018-06-05 10:56:19 +0000268void InstructionBenchmark::readYamlFrom(const BenchmarkResultContext &Context,
269 llvm::StringRef InputContent) {
Guillaume Chatelet083a0c162018-06-07 07:40:40 +0000270 llvm::yaml::Input Yin(InputContent, getUntypedContext(Context));
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000271 Yin >> *this;
272}
273
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000274llvm::Error
275InstructionBenchmark::writeYaml(const BenchmarkResultContext &Context,
276 const llvm::StringRef Filename) {
Clement Courbetac74acd2018-04-04 11:37:06 +0000277 if (Filename == "-") {
Clement Courbet53d35d22018-06-05 10:56:19 +0000278 writeYamlTo(Context, llvm::outs());
Clement Courbetac74acd2018-04-04 11:37:06 +0000279 } else {
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000280 int ResultFD = 0;
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000281 if (auto E = llvm::errorCodeToError(
Zachary Turner1f67a3c2018-06-07 19:58:58 +0000282 openFileForWrite(Filename, ResultFD, llvm::sys::fs::CD_CreateAlways,
283 llvm::sys::fs::F_Text))) {
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000284 return E;
285 }
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000286 llvm::raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/);
Clement Courbet53d35d22018-06-05 10:56:19 +0000287 writeYamlTo(Context, Ostr);
Clement Courbetac74acd2018-04-04 11:37:06 +0000288 }
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000289 return llvm::Error::success();
Clement Courbetac74acd2018-04-04 11:37:06 +0000290}
291
Clement Courbetae8ae5dc2018-05-24 12:41:02 +0000292void BenchmarkMeasureStats::push(const BenchmarkMeasure &BM) {
293 if (Key.empty())
294 Key = BM.Key;
295 assert(Key == BM.Key);
296 ++NumValues;
297 SumValues += BM.Value;
298 MaxValue = std::max(MaxValue, BM.Value);
299 MinValue = std::min(MinValue, BM.Value);
300}
301
Clement Courbetac74acd2018-04-04 11:37:06 +0000302} // namespace exegesis