blob: 9fe7a8463532b8ade133bb5c466dc5ba52aab5a5 [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"
13#include "llvm/Support/FileOutputBuffer.h"
14#include "llvm/Support/FileSystem.h"
15#include "llvm/Support/Format.h"
16#include "llvm/Support/raw_ostream.h"
17
Guillaume Chatelet083a0c162018-06-07 07:40:40 +000018static constexpr const char kIntegerFormat[] = "i_0x%" PRId64 "x";
19static constexpr const char kDoubleFormat[] = "f_%la";
20
21static void serialize(const exegesis::BenchmarkResultContext &Context,
22 const llvm::MCOperand &MCOperand, llvm::raw_ostream &OS) {
23 if (MCOperand.isReg()) {
24 OS << Context.getRegName(MCOperand.getReg());
25 } else if (MCOperand.isImm()) {
26 OS << llvm::format(kIntegerFormat, MCOperand.getImm());
27 } else if (MCOperand.isFPImm()) {
28 OS << llvm::format(kDoubleFormat, MCOperand.getFPImm());
29 } else {
30 OS << "INVALID";
31 }
32}
33
34static void serialize(const exegesis::BenchmarkResultContext &Context,
35 const llvm::MCInst &MCInst, llvm::raw_ostream &OS) {
36 OS << Context.getInstrName(MCInst.getOpcode());
37 for (const auto &Op : MCInst) {
38 OS << ' ';
39 serialize(Context, Op, OS);
40 }
41}
42
43static llvm::MCOperand
44deserialize(const exegesis::BenchmarkResultContext &Context,
45 llvm::StringRef String) {
46 assert(!String.empty());
47 int64_t IntValue = 0;
48 double DoubleValue = 0;
49 if (sscanf(String.data(), kIntegerFormat, &IntValue) == 1)
50 return llvm::MCOperand::createImm(IntValue);
51 if (sscanf(String.data(), kDoubleFormat, &DoubleValue) == 1)
52 return llvm::MCOperand::createFPImm(DoubleValue);
53 if (unsigned RegNo = Context.getRegNo(String)) // Returns 0 if invalid.
54 return llvm::MCOperand::createReg(RegNo);
55 return {};
56}
57
58static llvm::StringRef
59deserialize(const exegesis::BenchmarkResultContext &Context,
60 llvm::StringRef String, llvm::MCInst &Value) {
61 llvm::SmallVector<llvm::StringRef, 8> Pieces;
62 String.split(Pieces, " ");
63 if (Pieces.empty())
64 return "Invalid Instruction";
65 bool ProcessOpcode = true;
66 for (llvm::StringRef Piece : Pieces) {
67 if (ProcessOpcode) {
68 ProcessOpcode = false;
69 Value.setOpcode(Context.getInstrOpcode(Piece));
70 if (Value.getOpcode() == 0)
71 return "Unknown Opcode Name";
72 } else {
73 Value.addOperand(deserialize(Context, Piece));
74 }
75 }
76 return {};
77}
78
79// YAML IO requires a mutable pointer to Context but we guarantee to not
80// modify it.
81static void *getUntypedContext(const exegesis::BenchmarkResultContext &Ctx) {
82 return const_cast<exegesis::BenchmarkResultContext *>(&Ctx);
83}
84
85static const exegesis::BenchmarkResultContext &getTypedContext(void *Ctx) {
86 assert(Ctx);
87 return *static_cast<const exegesis::BenchmarkResultContext *>(Ctx);
88}
89
Clement Courbetac74acd2018-04-04 11:37:06 +000090// Defining YAML traits for IO.
91namespace llvm {
92namespace yaml {
93
Clement Courbet53d35d22018-06-05 10:56:19 +000094// std::vector<llvm::MCInst> will be rendered as a list.
95template <> struct SequenceElementTraits<llvm::MCInst> {
96 static const bool flow = false;
97};
98
99template <> struct ScalarTraits<llvm::MCInst> {
100
101 static void output(const llvm::MCInst &Value, void *Ctx,
102 llvm::raw_ostream &Out) {
Guillaume Chatelet083a0c162018-06-07 07:40:40 +0000103 serialize(getTypedContext(Ctx), Value, Out);
Clement Courbet53d35d22018-06-05 10:56:19 +0000104 }
105
106 static StringRef input(StringRef Scalar, void *Ctx, llvm::MCInst &Value) {
Guillaume Chatelet083a0c162018-06-07 07:40:40 +0000107 return deserialize(getTypedContext(Ctx), Scalar, Value);
Clement Courbet53d35d22018-06-05 10:56:19 +0000108 }
109
110 static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
111
112 static const bool flow = true;
113};
114
Clement Courbetac74acd2018-04-04 11:37:06 +0000115// std::vector<exegesis::Measure> will be rendered as a list.
116template <> struct SequenceElementTraits<exegesis::BenchmarkMeasure> {
117 static const bool flow = false;
118};
119
120// exegesis::Measure is rendererd as a flow instead of a list.
121// e.g. { "key": "the key", "value": 0123 }
122template <> struct MappingTraits<exegesis::BenchmarkMeasure> {
123 static void mapping(IO &Io, exegesis::BenchmarkMeasure &Obj) {
124 Io.mapRequired("key", Obj.Key);
125 Io.mapRequired("value", Obj.Value);
126 Io.mapOptional("debug_string", Obj.DebugString);
127 }
128 static const bool flow = true;
129};
130
Clement Courbet2cb97b92018-06-04 11:43:40 +0000131template <>
Clement Courbet62b34fa2018-06-06 09:42:36 +0000132struct ScalarEnumerationTraits<exegesis::InstructionBenchmark::ModeE> {
Clement Courbet2cb97b92018-06-04 11:43:40 +0000133 static void enumeration(IO &Io,
Clement Courbet62b34fa2018-06-06 09:42:36 +0000134 exegesis::InstructionBenchmark::ModeE &Value) {
135 Io.enumCase(Value, "", exegesis::InstructionBenchmark::Unknown);
136 Io.enumCase(Value, "latency", exegesis::InstructionBenchmark::Latency);
137 Io.enumCase(Value, "uops", exegesis::InstructionBenchmark::Uops);
Clement Courbet2cb97b92018-06-04 11:43:40 +0000138 }
139};
140
Clement Courbeta66bfaa42018-05-15 13:07:05 +0000141template <> struct MappingTraits<exegesis::InstructionBenchmarkKey> {
142 static void mapping(IO &Io, exegesis::InstructionBenchmarkKey &Obj) {
143 Io.mapRequired("opcode_name", Obj.OpcodeName);
Clement Courbet53d35d22018-06-05 10:56:19 +0000144 Io.mapOptional("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> {
150 static void mapping(IO &Io, exegesis::InstructionBenchmark &Obj) {
Clement Courbet62b34fa2018-06-06 09:42:36 +0000151 Io.mapRequired("mode", Obj.Mode);
Clement Courbeta66bfaa42018-05-15 13:07:05 +0000152 Io.mapRequired("key", Obj.Key);
Clement Courbetac74acd2018-04-04 11:37:06 +0000153 Io.mapRequired("cpu_name", Obj.CpuName);
154 Io.mapRequired("llvm_triple", Obj.LLVMTriple);
155 Io.mapRequired("num_repetitions", Obj.NumRepetitions);
156 Io.mapRequired("measurements", Obj.Measurements);
157 Io.mapRequired("error", Obj.Error);
Clement Courbeta66bfaa42018-05-15 13:07:05 +0000158 Io.mapOptional("info", Obj.Info);
Clement Courbetac74acd2018-04-04 11:37:06 +0000159 }
160};
161
162} // namespace yaml
163} // namespace llvm
164
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000165LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(exegesis::InstructionBenchmark)
166
Clement Courbetac74acd2018-04-04 11:37:06 +0000167namespace exegesis {
168
Clement Courbet53d35d22018-06-05 10:56:19 +0000169void BenchmarkResultContext::addRegEntry(unsigned RegNo, llvm::StringRef Name) {
170 assert(RegNoToName.find(RegNo) == RegNoToName.end());
171 assert(RegNameToNo.find(Name) == RegNameToNo.end());
172 RegNoToName[RegNo] = Name;
173 RegNameToNo[Name] = RegNo;
174}
175
176llvm::StringRef BenchmarkResultContext::getRegName(unsigned RegNo) const {
177 const auto Itr = RegNoToName.find(RegNo);
178 if (Itr != RegNoToName.end())
179 return Itr->second;
180 return {};
181}
182
183unsigned BenchmarkResultContext::getRegNo(llvm::StringRef Name) const {
184 const auto Itr = RegNameToNo.find(Name);
185 if (Itr != RegNameToNo.end())
186 return Itr->second;
187 return 0;
188}
189
190void BenchmarkResultContext::addInstrEntry(unsigned Opcode,
191 llvm::StringRef Name) {
192 assert(InstrOpcodeToName.find(Opcode) == InstrOpcodeToName.end());
193 assert(InstrNameToOpcode.find(Name) == InstrNameToOpcode.end());
194 InstrOpcodeToName[Opcode] = Name;
195 InstrNameToOpcode[Name] = Opcode;
196}
197
198llvm::StringRef BenchmarkResultContext::getInstrName(unsigned Opcode) const {
199 const auto Itr = InstrOpcodeToName.find(Opcode);
200 if (Itr != InstrOpcodeToName.end())
201 return Itr->second;
202 return {};
203}
204
205unsigned BenchmarkResultContext::getInstrOpcode(llvm::StringRef Name) const {
206 const auto Itr = InstrNameToOpcode.find(Name);
207 if (Itr != InstrNameToOpcode.end())
208 return Itr->second;
209 return 0;
210}
211
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000212template <typename ObjectOrList>
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000213static llvm::Expected<ObjectOrList>
214readYamlCommon(const BenchmarkResultContext &Context,
215 llvm::StringRef Filename) {
216 if (auto ExpectedMemoryBuffer =
217 llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename))) {
218 std::unique_ptr<llvm::MemoryBuffer> MemoryBuffer =
219 std::move(ExpectedMemoryBuffer.get());
220 llvm::yaml::Input Yin(*MemoryBuffer, getUntypedContext(Context));
221 ObjectOrList Benchmark;
222 Yin >> Benchmark;
223 return Benchmark;
224 } else {
225 return ExpectedMemoryBuffer.takeError();
226 }
Clement Courbetac74acd2018-04-04 11:37:06 +0000227}
228
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000229llvm::Expected<InstructionBenchmark>
230InstructionBenchmark::readYaml(const BenchmarkResultContext &Context,
231 llvm::StringRef Filename) {
232 return readYamlCommon<InstructionBenchmark>(Context, Filename);
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000233}
234
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000235llvm::Expected<std::vector<InstructionBenchmark>>
236InstructionBenchmark::readYamls(const BenchmarkResultContext &Context,
237 llvm::StringRef Filename) {
238 return readYamlCommon<std::vector<InstructionBenchmark>>(Context, Filename);
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000239}
240
Clement Courbet53d35d22018-06-05 10:56:19 +0000241void InstructionBenchmark::writeYamlTo(const BenchmarkResultContext &Context,
Guillaume Chatelet083a0c162018-06-07 07:40:40 +0000242 llvm::raw_ostream &OS) {
243 llvm::yaml::Output Yout(OS, getUntypedContext(Context));
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000244 Yout << *this;
245}
246
Clement Courbet53d35d22018-06-05 10:56:19 +0000247void InstructionBenchmark::readYamlFrom(const BenchmarkResultContext &Context,
248 llvm::StringRef InputContent) {
Guillaume Chatelet083a0c162018-06-07 07:40:40 +0000249 llvm::yaml::Input Yin(InputContent, getUntypedContext(Context));
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000250 Yin >> *this;
251}
252
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000253llvm::Error
254InstructionBenchmark::writeYaml(const BenchmarkResultContext &Context,
255 const llvm::StringRef Filename) {
Clement Courbetac74acd2018-04-04 11:37:06 +0000256 if (Filename == "-") {
Clement Courbet53d35d22018-06-05 10:56:19 +0000257 writeYamlTo(Context, llvm::outs());
Clement Courbetac74acd2018-04-04 11:37:06 +0000258 } else {
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000259 int ResultFD = 0;
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000260 if (auto E = llvm::errorCodeToError(
261 openFileForWrite(Filename, ResultFD, llvm::sys::fs::F_Text))) {
262 return E;
263 }
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000264 llvm::raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/);
Clement Courbet53d35d22018-06-05 10:56:19 +0000265 writeYamlTo(Context, Ostr);
Clement Courbetac74acd2018-04-04 11:37:06 +0000266 }
Guillaume Chatelet8c91d4c2018-06-07 07:51:16 +0000267 return llvm::Error::success();
Clement Courbetac74acd2018-04-04 11:37:06 +0000268}
269
Clement Courbetae8ae5dc2018-05-24 12:41:02 +0000270void BenchmarkMeasureStats::push(const BenchmarkMeasure &BM) {
271 if (Key.empty())
272 Key = BM.Key;
273 assert(Key == BM.Key);
274 ++NumValues;
275 SumValues += BM.Value;
276 MaxValue = std::max(MaxValue, BM.Value);
277 MinValue = std::min(MinValue, BM.Value);
278}
279
Clement Courbetac74acd2018-04-04 11:37:06 +0000280} // namespace exegesis