blob: ed8531f4400362c559bd2b7e8b9862dfcdc3989f [file] [log] [blame]
Clement Courbetac74acd2018-04-04 11:37:06 +00001//===-- BenchmarkResult.cpp -------------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Clement Courbetac74acd2018-04-04 11:37:06 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "BenchmarkResult.h"
Guillaume Chatelet55ad0872018-09-25 12:18:08 +000010#include "BenchmarkRunner.h"
Clement Courbet53d35d22018-06-05 10:56:19 +000011#include "llvm/ADT/STLExtras.h"
Roman Lebedev5b94fe92019-02-04 09:12:21 +000012#include "llvm/ADT/StringMap.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000013#include "llvm/ADT/StringRef.h"
Roman Lebedev5b94fe92019-02-04 09:12:21 +000014#include "llvm/ADT/bit.h"
Clement Courbet4273e1e2018-06-15 07:30:45 +000015#include "llvm/ObjectYAML/YAML.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000016#include "llvm/Support/FileOutputBuffer.h"
17#include "llvm/Support/FileSystem.h"
18#include "llvm/Support/Format.h"
19#include "llvm/Support/raw_ostream.h"
20
Guillaume Chatelet9157bc92018-10-04 12:33:46 +000021static constexpr const char kIntegerPrefix[] = "i_0x";
22static constexpr const char kDoublePrefix[] = "f_";
Guillaume Chatelet55ad0872018-09-25 12:18:08 +000023static constexpr const char kInvalidOperand[] = "INVALID";
Guillaume Chatelet083a0c162018-06-07 07:40:40 +000024
Fangrui Song32401af2018-10-22 17:10:47 +000025namespace llvm {
26
27namespace {
28
Guillaume Chatelet55ad0872018-09-25 12:18:08 +000029// A mutable struct holding an LLVMState that can be passed through the
30// serialization process to encode/decode registers and instructions.
31struct YamlContext {
32 YamlContext(const exegesis::LLVMState &State)
Roman Lebedev5b94fe92019-02-04 09:12:21 +000033 : State(&State), ErrorStream(LastError),
34 OpcodeNameToOpcodeIdx(
Roman Lebedevbd84b132019-02-04 09:12:25 +000035 generateOpcodeNameToOpcodeIdxMapping(State.getInstrInfo())),
36 RegNameToRegNo(generateRegNameToRegNoMapping(State.getRegInfo())) {}
Roman Lebedev5b94fe92019-02-04 09:12:21 +000037
38 static llvm::StringMap<unsigned>
39 generateOpcodeNameToOpcodeIdxMapping(const llvm::MCInstrInfo &InstrInfo) {
40 llvm::StringMap<unsigned> Map(InstrInfo.getNumOpcodes());
41 for (unsigned I = 0, E = InstrInfo.getNumOpcodes(); I < E; ++I)
42 Map[InstrInfo.getName(I)] = I;
43 assert(Map.size() == InstrInfo.getNumOpcodes() && "Size prediction failed");
44 return Map;
45 };
Guillaume Chatelet083a0c162018-06-07 07:40:40 +000046
Roman Lebedevbd84b132019-02-04 09:12:25 +000047 llvm::StringMap<unsigned>
48 generateRegNameToRegNoMapping(const llvm::MCRegisterInfo &RegInfo) {
49 llvm::StringMap<unsigned> Map(RegInfo.getNumRegs());
50 for (unsigned I = 0, E = RegInfo.getNumRegs(); I < E; ++I)
51 Map[RegInfo.getName(I)] = I;
52 assert(Map.size() == RegInfo.getNumRegs() && "Size prediction failed");
53 return Map;
54 };
55
Guillaume Chatelet55ad0872018-09-25 12:18:08 +000056 void serializeMCInst(const llvm::MCInst &MCInst, llvm::raw_ostream &OS) {
57 OS << getInstrName(MCInst.getOpcode());
58 for (const auto &Op : MCInst) {
59 OS << ' ';
60 serializeMCOperand(Op, OS);
Guillaume Chatelet083a0c162018-06-07 07:40:40 +000061 }
62 }
Guillaume Chatelet083a0c162018-06-07 07:40:40 +000063
Guillaume Chatelet55ad0872018-09-25 12:18:08 +000064 void deserializeMCInst(llvm::StringRef String, llvm::MCInst &Value) {
Roman Lebedevdc78bc22019-02-04 09:12:13 +000065 llvm::SmallVector<llvm::StringRef, 16> Pieces;
Guillaume Chatelet55ad0872018-09-25 12:18:08 +000066 String.split(Pieces, " ", /* MaxSplit */ -1, /* KeepEmpty */ false);
67 if (Pieces.empty()) {
68 ErrorStream << "Unknown Instruction: '" << String << "'";
69 return;
70 }
71 bool ProcessOpcode = true;
72 for (llvm::StringRef Piece : Pieces) {
73 if (ProcessOpcode)
74 Value.setOpcode(getInstrOpcode(Piece));
75 else
76 Value.addOperand(deserializeMCOperand(Piece));
77 ProcessOpcode = false;
78 }
79 }
Guillaume Chatelet083a0c162018-06-07 07:40:40 +000080
Guillaume Chatelet55ad0872018-09-25 12:18:08 +000081 std::string &getLastError() { return ErrorStream.str(); }
82
Guillaume Chatelet345fae52018-09-25 15:15:54 +000083 llvm::raw_string_ostream &getErrorStream() { return ErrorStream; }
84
85 llvm::StringRef getRegName(unsigned RegNo) {
86 const llvm::StringRef RegName = State->getRegInfo().getName(RegNo);
87 if (RegName.empty())
88 ErrorStream << "No register with enum value" << RegNo;
89 return RegName;
90 }
91
92 unsigned getRegNo(llvm::StringRef RegName) {
Roman Lebedevbd84b132019-02-04 09:12:25 +000093 auto Iter = RegNameToRegNo.find(RegName);
94 if (Iter != RegNameToRegNo.end())
95 return Iter->second;
Guillaume Chatelet345fae52018-09-25 15:15:54 +000096 ErrorStream << "No register with name " << RegName;
97 return 0;
98 }
99
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000100private:
Guillaume Chatelet9157bc92018-10-04 12:33:46 +0000101 void serializeIntegerOperand(llvm::raw_ostream &OS, int64_t Value) {
102 OS << kIntegerPrefix;
103 OS.write_hex(llvm::bit_cast<uint64_t>(Value));
104 }
105
106 bool tryDeserializeIntegerOperand(llvm::StringRef String, int64_t &Value) {
107 if (!String.consume_front(kIntegerPrefix))
108 return false;
109 return !String.consumeInteger(16, Value);
110 }
111
112 void serializeFPOperand(llvm::raw_ostream &OS, double Value) {
113 OS << kDoublePrefix << llvm::format("%la", Value);
114 }
115
116 bool tryDeserializeFPOperand(llvm::StringRef String, double &Value) {
117 if (!String.consume_front(kDoublePrefix))
118 return false;
119 char *EndPointer = nullptr;
120 Value = strtod(String.begin(), &EndPointer);
121 return EndPointer == String.end();
122 }
123
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000124 void serializeMCOperand(const llvm::MCOperand &MCOperand,
125 llvm::raw_ostream &OS) {
126 if (MCOperand.isReg()) {
127 OS << getRegName(MCOperand.getReg());
128 } else if (MCOperand.isImm()) {
Guillaume Chatelet9157bc92018-10-04 12:33:46 +0000129 serializeIntegerOperand(OS, MCOperand.getImm());
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000130 } else if (MCOperand.isFPImm()) {
Guillaume Chatelet9157bc92018-10-04 12:33:46 +0000131 serializeFPOperand(OS, MCOperand.getFPImm());
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000132 } else {
133 OS << kInvalidOperand;
134 }
135 }
136
137 llvm::MCOperand deserializeMCOperand(llvm::StringRef String) {
138 assert(!String.empty());
139 int64_t IntValue = 0;
140 double DoubleValue = 0;
Guillaume Chatelet9157bc92018-10-04 12:33:46 +0000141 if (tryDeserializeIntegerOperand(String, IntValue))
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000142 return llvm::MCOperand::createImm(IntValue);
Guillaume Chatelet9157bc92018-10-04 12:33:46 +0000143 if (tryDeserializeFPOperand(String, DoubleValue))
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000144 return llvm::MCOperand::createFPImm(DoubleValue);
145 if (unsigned RegNo = getRegNo(String))
146 return llvm::MCOperand::createReg(RegNo);
147 if (String != kInvalidOperand)
148 ErrorStream << "Unknown Operand: '" << String << "'";
149 return {};
150 }
151
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000152 llvm::StringRef getInstrName(unsigned InstrNo) {
153 const llvm::StringRef InstrName = State->getInstrInfo().getName(InstrNo);
154 if (InstrName.empty())
155 ErrorStream << "No opcode with enum value" << InstrNo;
156 return InstrName;
157 }
158
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000159 unsigned getInstrOpcode(llvm::StringRef InstrName) {
Roman Lebedev5b94fe92019-02-04 09:12:21 +0000160 auto Iter = OpcodeNameToOpcodeIdx.find(InstrName);
161 if (Iter != OpcodeNameToOpcodeIdx.end())
162 return Iter->second;
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000163 ErrorStream << "No opcode with name " << InstrName;
164 return 0;
165 }
166
Fangrui Song32401af2018-10-22 17:10:47 +0000167 const llvm::exegesis::LLVMState *State;
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000168 std::string LastError;
169 llvm::raw_string_ostream ErrorStream;
Roman Lebedev5b94fe92019-02-04 09:12:21 +0000170 const llvm::StringMap<unsigned> OpcodeNameToOpcodeIdx;
Roman Lebedevbd84b132019-02-04 09:12:25 +0000171 const llvm::StringMap<unsigned> RegNameToRegNo;
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000172};
Fangrui Song32401af2018-10-22 17:10:47 +0000173} // namespace
Guillaume Chatelet083a0c162018-06-07 07:40:40 +0000174
Clement Courbetac74acd2018-04-04 11:37:06 +0000175// Defining YAML traits for IO.
Clement Courbetac74acd2018-04-04 11:37:06 +0000176namespace yaml {
177
Guillaume Chatelet345fae52018-09-25 15:15:54 +0000178static YamlContext &getTypedContext(void *Ctx) {
179 return *reinterpret_cast<YamlContext *>(Ctx);
180}
181
Clement Courbet53d35d22018-06-05 10:56:19 +0000182// std::vector<llvm::MCInst> will be rendered as a list.
183template <> struct SequenceElementTraits<llvm::MCInst> {
184 static const bool flow = false;
185};
186
187template <> struct ScalarTraits<llvm::MCInst> {
188
189 static void output(const llvm::MCInst &Value, void *Ctx,
190 llvm::raw_ostream &Out) {
Guillaume Chatelet345fae52018-09-25 15:15:54 +0000191 getTypedContext(Ctx).serializeMCInst(Value, Out);
Clement Courbet53d35d22018-06-05 10:56:19 +0000192 }
193
194 static StringRef input(StringRef Scalar, void *Ctx, llvm::MCInst &Value) {
Guillaume Chatelet345fae52018-09-25 15:15:54 +0000195 YamlContext &Context = getTypedContext(Ctx);
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000196 Context.deserializeMCInst(Scalar, Value);
197 return Context.getLastError();
Clement Courbet53d35d22018-06-05 10:56:19 +0000198 }
199
Guillaume Chatelet345fae52018-09-25 15:15:54 +0000200 // By default strings are quoted only when necessary.
201 // We force the use of single quotes for uniformity.
Clement Courbet53d35d22018-06-05 10:56:19 +0000202 static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
203
204 static const bool flow = true;
205};
206
Clement Courbetac74acd2018-04-04 11:37:06 +0000207// std::vector<exegesis::Measure> will be rendered as a list.
208template <> struct SequenceElementTraits<exegesis::BenchmarkMeasure> {
209 static const bool flow = false;
210};
211
212// exegesis::Measure is rendererd as a flow instead of a list.
213// e.g. { "key": "the key", "value": 0123 }
214template <> struct MappingTraits<exegesis::BenchmarkMeasure> {
215 static void mapping(IO &Io, exegesis::BenchmarkMeasure &Obj) {
Clement Courbet28d4f852018-09-26 13:35:10 +0000216 Io.mapRequired("key", Obj.Key);
217 if (!Io.outputting()) {
218 // For backward compatibility, interpret debug_string as a key.
219 Io.mapOptional("debug_string", Obj.Key);
220 }
Clement Courbet684a5f62018-09-26 08:37:21 +0000221 Io.mapRequired("value", Obj.PerInstructionValue);
222 Io.mapOptional("per_snippet_value", Obj.PerSnippetValue);
Clement Courbetac74acd2018-04-04 11:37:06 +0000223 }
224 static const bool flow = true;
225};
226
Clement Courbet2cb97b92018-06-04 11:43:40 +0000227template <>
Clement Courbet62b34fa2018-06-06 09:42:36 +0000228struct ScalarEnumerationTraits<exegesis::InstructionBenchmark::ModeE> {
Clement Courbet2cb97b92018-06-04 11:43:40 +0000229 static void enumeration(IO &Io,
Clement Courbet62b34fa2018-06-06 09:42:36 +0000230 exegesis::InstructionBenchmark::ModeE &Value) {
231 Io.enumCase(Value, "", exegesis::InstructionBenchmark::Unknown);
232 Io.enumCase(Value, "latency", exegesis::InstructionBenchmark::Latency);
233 Io.enumCase(Value, "uops", exegesis::InstructionBenchmark::Uops);
Clement Courbet362653f2019-01-30 16:02:20 +0000234 Io.enumCase(Value, "inverse_throughput",
235 exegesis::InstructionBenchmark::InverseThroughput);
Clement Courbet2cb97b92018-06-04 11:43:40 +0000236 }
237};
238
Guillaume Chatelet345fae52018-09-25 15:15:54 +0000239// std::vector<exegesis::RegisterValue> will be rendered as a list.
240template <> struct SequenceElementTraits<exegesis::RegisterValue> {
241 static const bool flow = false;
242};
243
244template <> struct ScalarTraits<exegesis::RegisterValue> {
245 static constexpr const unsigned kRadix = 16;
246 static constexpr const bool kSigned = false;
247
248 static void output(const exegesis::RegisterValue &RV, void *Ctx,
249 llvm::raw_ostream &Out) {
250 YamlContext &Context = getTypedContext(Ctx);
251 Out << Context.getRegName(RV.Register) << "=0x"
252 << RV.Value.toString(kRadix, kSigned);
253 }
254
255 static StringRef input(StringRef String, void *Ctx,
256 exegesis::RegisterValue &RV) {
257 llvm::SmallVector<llvm::StringRef, 2> Pieces;
258 String.split(Pieces, "=0x", /* MaxSplit */ -1,
259 /* KeepEmpty */ false);
260 YamlContext &Context = getTypedContext(Ctx);
261 if (Pieces.size() == 2) {
262 RV.Register = Context.getRegNo(Pieces[0]);
263 const unsigned BitsNeeded = llvm::APInt::getBitsNeeded(Pieces[1], kRadix);
264 RV.Value = llvm::APInt(BitsNeeded, Pieces[1], kRadix);
265 } else {
266 Context.getErrorStream()
267 << "Unknown initial register value: '" << String << "'";
268 }
269 return Context.getLastError();
270 }
271
272 static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
273
274 static const bool flow = true;
275};
276
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000277template <>
278struct MappingContextTraits<exegesis::InstructionBenchmarkKey, YamlContext> {
279 static void mapping(IO &Io, exegesis::InstructionBenchmarkKey &Obj,
280 YamlContext &Context) {
281 Io.setContext(&Context);
Clement Courbet49fad1c2018-06-14 06:57:52 +0000282 Io.mapRequired("instructions", Obj.Instructions);
Clement Courbeta66bfaa42018-05-15 13:07:05 +0000283 Io.mapOptional("config", Obj.Config);
Guillaume Chatelet345fae52018-09-25 15:15:54 +0000284 Io.mapRequired("register_initial_values", Obj.RegisterInitialValues);
Clement Courbetac74acd2018-04-04 11:37:06 +0000285 }
286};
287
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000288template <>
289struct MappingContextTraits<exegesis::InstructionBenchmark, YamlContext> {
Guillaume Chatelet345fae52018-09-25 15:15:54 +0000290 struct NormalizedBinary {
Clement Courbet4273e1e2018-06-15 07:30:45 +0000291 NormalizedBinary(IO &io) {}
292 NormalizedBinary(IO &, std::vector<uint8_t> &Data) : Binary(Data) {}
293 std::vector<uint8_t> denormalize(IO &) {
294 std::vector<uint8_t> Data;
295 std::string Str;
296 raw_string_ostream OSS(Str);
297 Binary.writeAsBinary(OSS);
298 OSS.flush();
299 Data.assign(Str.begin(), Str.end());
300 return Data;
301 }
302
303 BinaryRef Binary;
304 };
305
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000306 static void mapping(IO &Io, exegesis::InstructionBenchmark &Obj,
307 YamlContext &Context) {
Clement Courbet62b34fa2018-06-06 09:42:36 +0000308 Io.mapRequired("mode", Obj.Mode);
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000309 Io.mapRequired("key", Obj.Key, Context);
Clement Courbetac74acd2018-04-04 11:37:06 +0000310 Io.mapRequired("cpu_name", Obj.CpuName);
311 Io.mapRequired("llvm_triple", Obj.LLVMTriple);
312 Io.mapRequired("num_repetitions", Obj.NumRepetitions);
313 Io.mapRequired("measurements", Obj.Measurements);
314 Io.mapRequired("error", Obj.Error);
Clement Courbeta66bfaa42018-05-15 13:07:05 +0000315 Io.mapOptional("info", Obj.Info);
Clement Courbet4273e1e2018-06-15 07:30:45 +0000316 // AssembledSnippet
317 MappingNormalization<NormalizedBinary, std::vector<uint8_t>> BinaryString(
318 Io, Obj.AssembledSnippet);
319 Io.mapOptional("assembled_snippet", BinaryString->Binary);
Clement Courbetac74acd2018-04-04 11:37:06 +0000320 }
321};
322
323} // namespace yaml
Clement Courbetac74acd2018-04-04 11:37:06 +0000324
325namespace exegesis {
326
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000327llvm::Expected<InstructionBenchmark>
328InstructionBenchmark::readYaml(const LLVMState &State,
329 llvm::StringRef Filename) {
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000330 if (auto ExpectedMemoryBuffer =
331 llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename))) {
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000332 llvm::yaml::Input Yin(*ExpectedMemoryBuffer.get());
333 YamlContext Context(State);
334 InstructionBenchmark Benchmark;
335 if (Yin.setCurrentDocument())
336 llvm::yaml::yamlize(Yin, Benchmark, /*unused*/ true, Context);
337 if (!Context.getLastError().empty())
338 return llvm::make_error<BenchmarkFailure>(Context.getLastError());
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000339 return Benchmark;
340 } else {
341 return ExpectedMemoryBuffer.takeError();
342 }
Clement Courbetac74acd2018-04-04 11:37:06 +0000343}
344
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000345llvm::Expected<std::vector<InstructionBenchmark>>
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000346InstructionBenchmark::readYamls(const LLVMState &State,
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000347 llvm::StringRef Filename) {
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000348 if (auto ExpectedMemoryBuffer =
349 llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename))) {
350 llvm::yaml::Input Yin(*ExpectedMemoryBuffer.get());
351 YamlContext Context(State);
352 std::vector<InstructionBenchmark> Benchmarks;
353 while (Yin.setCurrentDocument()) {
354 Benchmarks.emplace_back();
355 yamlize(Yin, Benchmarks.back(), /*unused*/ true, Context);
356 if (Yin.error())
357 return llvm::errorCodeToError(Yin.error());
358 if (!Context.getLastError().empty())
359 return llvm::make_error<BenchmarkFailure>(Context.getLastError());
360 Yin.nextDocument();
361 }
362 return Benchmarks;
363 } else {
364 return ExpectedMemoryBuffer.takeError();
365 }
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000366}
367
Roman Lebedev628f1ae2019-04-10 12:19:57 +0000368llvm::Error InstructionBenchmark::writeYamlTo(const LLVMState &State,
369 llvm::raw_ostream &OS) {
Clement Courbet70667692018-11-07 15:46:45 +0000370 llvm::yaml::Output Yout(OS, nullptr /*Ctx*/, 200 /*WrapColumn*/);
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000371 YamlContext Context(State);
Guillaume Chatelet6078f822018-09-25 14:48:24 +0000372 Yout.beginDocuments();
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000373 llvm::yaml::yamlize(Yout, *this, /*unused*/ true, Context);
Roman Lebedev628f1ae2019-04-10 12:19:57 +0000374 if (!Context.getLastError().empty())
375 return llvm::make_error<BenchmarkFailure>(Context.getLastError());
Guillaume Chatelet6078f822018-09-25 14:48:24 +0000376 Yout.endDocuments();
Roman Lebedev628f1ae2019-04-10 12:19:57 +0000377 return Error::success();
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000378}
379
Roman Lebedev628f1ae2019-04-10 12:19:57 +0000380llvm::Error InstructionBenchmark::readYamlFrom(const LLVMState &State,
381 llvm::StringRef InputContent) {
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000382 llvm::yaml::Input Yin(InputContent);
383 YamlContext Context(State);
384 if (Yin.setCurrentDocument())
385 llvm::yaml::yamlize(Yin, *this, /*unused*/ true, Context);
Roman Lebedev628f1ae2019-04-10 12:19:57 +0000386 if (!Context.getLastError().empty())
387 return llvm::make_error<BenchmarkFailure>(Context.getLastError());
388 return Error::success();
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000389}
390
Guillaume Chatelet55ad0872018-09-25 12:18:08 +0000391llvm::Error InstructionBenchmark::writeYaml(const LLVMState &State,
392 const llvm::StringRef Filename) {
Clement Courbetac74acd2018-04-04 11:37:06 +0000393 if (Filename == "-") {
Roman Lebedev628f1ae2019-04-10 12:19:57 +0000394 if (auto Err = writeYamlTo(State, llvm::outs()))
395 return std::move(Err);
Clement Courbetac74acd2018-04-04 11:37:06 +0000396 } else {
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000397 int ResultFD = 0;
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000398 if (auto E = llvm::errorCodeToError(
Zachary Turner1f67a3c2018-06-07 19:58:58 +0000399 openFileForWrite(Filename, ResultFD, llvm::sys::fs::CD_CreateAlways,
400 llvm::sys::fs::F_Text))) {
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000401 return E;
402 }
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000403 llvm::raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/);
Roman Lebedev628f1ae2019-04-10 12:19:57 +0000404 if (auto Err = writeYamlTo(State, Ostr))
405 return std::move(Err);
Clement Courbetac74acd2018-04-04 11:37:06 +0000406 }
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000407 return llvm::Error::success();
Clement Courbetac74acd2018-04-04 11:37:06 +0000408}
409
Clement Courbet684a5f62018-09-26 08:37:21 +0000410void PerInstructionStats::push(const BenchmarkMeasure &BM) {
Clement Courbetae8ae5dc2018-05-24 12:41:02 +0000411 if (Key.empty())
412 Key = BM.Key;
413 assert(Key == BM.Key);
414 ++NumValues;
Clement Courbet684a5f62018-09-26 08:37:21 +0000415 SumValues += BM.PerInstructionValue;
416 MaxValue = std::max(MaxValue, BM.PerInstructionValue);
417 MinValue = std::min(MinValue, BM.PerInstructionValue);
Clement Courbetae8ae5dc2018-05-24 12:41:02 +0000418}
419
Clement Courbetac74acd2018-04-04 11:37:06 +0000420} // namespace exegesis
Fangrui Song32401af2018-10-22 17:10:47 +0000421} // namespace llvm