blob: 441aee0758ee72ef5edaa7dfaab79ab3e5bf610b [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
18// Defining YAML traits for IO.
19namespace llvm {
20namespace yaml {
21
Clement Courbet53d35d22018-06-05 10:56:19 +000022// std::vector<llvm::MCInst> will be rendered as a list.
23template <> struct SequenceElementTraits<llvm::MCInst> {
24 static const bool flow = false;
25};
26
27template <> struct ScalarTraits<llvm::MCInst> {
28
29 static void output(const llvm::MCInst &Value, void *Ctx,
30 llvm::raw_ostream &Out) {
31 assert(Ctx);
32 auto *Context = static_cast<const exegesis::BenchmarkResultContext *>(Ctx);
33 const StringRef Name = Context->getInstrName(Value.getOpcode());
34 assert(!Name.empty());
35 Out << Name;
36 }
37
38 static StringRef input(StringRef Scalar, void *Ctx, llvm::MCInst &Value) {
39 assert(Ctx);
40 auto *Context = static_cast<const exegesis::BenchmarkResultContext *>(Ctx);
41 const unsigned Opcode = Context->getInstrOpcode(Scalar);
42 if (Opcode == 0) {
43 return "Unable to parse instruction";
44 }
45 Value.setOpcode(Opcode);
46 return StringRef();
47 }
48
49 static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
50
51 static const bool flow = true;
52};
53
Clement Courbetac74acd2018-04-04 11:37:06 +000054// std::vector<exegesis::Measure> will be rendered as a list.
55template <> struct SequenceElementTraits<exegesis::BenchmarkMeasure> {
56 static const bool flow = false;
57};
58
59// exegesis::Measure is rendererd as a flow instead of a list.
60// e.g. { "key": "the key", "value": 0123 }
61template <> struct MappingTraits<exegesis::BenchmarkMeasure> {
62 static void mapping(IO &Io, exegesis::BenchmarkMeasure &Obj) {
63 Io.mapRequired("key", Obj.Key);
64 Io.mapRequired("value", Obj.Value);
65 Io.mapOptional("debug_string", Obj.DebugString);
66 }
67 static const bool flow = true;
68};
69
Clement Courbet2cb97b92018-06-04 11:43:40 +000070template <>
71struct ScalarEnumerationTraits<exegesis::InstructionBenchmarkKey::ModeE> {
72 static void enumeration(IO &Io,
73 exegesis::InstructionBenchmarkKey::ModeE &Value) {
74 Io.enumCase(Value, "", exegesis::InstructionBenchmarkKey::Unknown);
75 Io.enumCase(Value, "latency", exegesis::InstructionBenchmarkKey::Latency);
76 Io.enumCase(Value, "uops", exegesis::InstructionBenchmarkKey::Uops);
77 }
78};
79
Clement Courbeta66bfaa42018-05-15 13:07:05 +000080template <> struct MappingTraits<exegesis::InstructionBenchmarkKey> {
81 static void mapping(IO &Io, exegesis::InstructionBenchmarkKey &Obj) {
82 Io.mapRequired("opcode_name", Obj.OpcodeName);
Clement Courbet53d35d22018-06-05 10:56:19 +000083 Io.mapOptional("instructions", Obj.Instructions);
Clement Courbeta66bfaa42018-05-15 13:07:05 +000084 Io.mapRequired("mode", Obj.Mode);
85 Io.mapOptional("config", Obj.Config);
Clement Courbetac74acd2018-04-04 11:37:06 +000086 }
87};
88
89template <> struct MappingTraits<exegesis::InstructionBenchmark> {
90 static void mapping(IO &Io, exegesis::InstructionBenchmark &Obj) {
Clement Courbeta66bfaa42018-05-15 13:07:05 +000091 Io.mapRequired("key", Obj.Key);
Clement Courbetac74acd2018-04-04 11:37:06 +000092 Io.mapRequired("cpu_name", Obj.CpuName);
93 Io.mapRequired("llvm_triple", Obj.LLVMTriple);
94 Io.mapRequired("num_repetitions", Obj.NumRepetitions);
95 Io.mapRequired("measurements", Obj.Measurements);
96 Io.mapRequired("error", Obj.Error);
Clement Courbeta66bfaa42018-05-15 13:07:05 +000097 Io.mapOptional("info", Obj.Info);
Clement Courbetac74acd2018-04-04 11:37:06 +000098 }
99};
100
101} // namespace yaml
102} // namespace llvm
103
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000104LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(exegesis::InstructionBenchmark)
105
Clement Courbetac74acd2018-04-04 11:37:06 +0000106namespace exegesis {
107
Clement Courbet53d35d22018-06-05 10:56:19 +0000108void BenchmarkResultContext::addRegEntry(unsigned RegNo, llvm::StringRef Name) {
109 assert(RegNoToName.find(RegNo) == RegNoToName.end());
110 assert(RegNameToNo.find(Name) == RegNameToNo.end());
111 RegNoToName[RegNo] = Name;
112 RegNameToNo[Name] = RegNo;
113}
114
115llvm::StringRef BenchmarkResultContext::getRegName(unsigned RegNo) const {
116 const auto Itr = RegNoToName.find(RegNo);
117 if (Itr != RegNoToName.end())
118 return Itr->second;
119 return {};
120}
121
122unsigned BenchmarkResultContext::getRegNo(llvm::StringRef Name) const {
123 const auto Itr = RegNameToNo.find(Name);
124 if (Itr != RegNameToNo.end())
125 return Itr->second;
126 return 0;
127}
128
129void BenchmarkResultContext::addInstrEntry(unsigned Opcode,
130 llvm::StringRef Name) {
131 assert(InstrOpcodeToName.find(Opcode) == InstrOpcodeToName.end());
132 assert(InstrNameToOpcode.find(Name) == InstrNameToOpcode.end());
133 InstrOpcodeToName[Opcode] = Name;
134 InstrNameToOpcode[Name] = Opcode;
135}
136
137llvm::StringRef BenchmarkResultContext::getInstrName(unsigned Opcode) const {
138 const auto Itr = InstrOpcodeToName.find(Opcode);
139 if (Itr != InstrOpcodeToName.end())
140 return Itr->second;
141 return {};
142}
143
144unsigned BenchmarkResultContext::getInstrOpcode(llvm::StringRef Name) const {
145 const auto Itr = InstrNameToOpcode.find(Name);
146 if (Itr != InstrNameToOpcode.end())
147 return Itr->second;
148 return 0;
149}
150
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000151template <typename ObjectOrList>
Clement Courbet53d35d22018-06-05 10:56:19 +0000152static ObjectOrList readYamlOrDieCommon(const BenchmarkResultContext &Context,
153 llvm::StringRef Filename) {
Clement Courbetac74acd2018-04-04 11:37:06 +0000154 std::unique_ptr<llvm::MemoryBuffer> MemBuffer = llvm::cantFail(
155 llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename)));
Clement Courbet53d35d22018-06-05 10:56:19 +0000156 // YAML IO requires a mutable pointer to Context but we guarantee to not
157 // modify it.
158 llvm::yaml::Input Yin(*MemBuffer,
159 const_cast<BenchmarkResultContext *>(&Context));
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000160 ObjectOrList Benchmark;
Clement Courbetac74acd2018-04-04 11:37:06 +0000161 Yin >> Benchmark;
162 return Benchmark;
163}
164
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000165InstructionBenchmark
Clement Courbet53d35d22018-06-05 10:56:19 +0000166InstructionBenchmark::readYamlOrDie(const BenchmarkResultContext &Context,
167 llvm::StringRef Filename) {
168 return readYamlOrDieCommon<InstructionBenchmark>(Context, Filename);
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000169}
170
171std::vector<InstructionBenchmark>
Clement Courbet53d35d22018-06-05 10:56:19 +0000172InstructionBenchmark::readYamlsOrDie(const BenchmarkResultContext &Context,
173 llvm::StringRef Filename) {
174 return readYamlOrDieCommon<std::vector<InstructionBenchmark>>(Context,
175 Filename);
Clement Courbet7b7c27a2018-05-14 09:01:22 +0000176}
177
Clement Courbet53d35d22018-06-05 10:56:19 +0000178void InstructionBenchmark::writeYamlTo(const BenchmarkResultContext &Context,
179 llvm::raw_ostream &S) {
180 // YAML IO requires a mutable pointer to Context but we guarantee to not
181 // modify it.
182 llvm::yaml::Output Yout(S, const_cast<BenchmarkResultContext *>(&Context));
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000183 Yout << *this;
184}
185
Clement Courbet53d35d22018-06-05 10:56:19 +0000186void InstructionBenchmark::readYamlFrom(const BenchmarkResultContext &Context,
187 llvm::StringRef InputContent) {
188 // YAML IO requires a mutable pointer to Context but we guarantee to not
189 // modify it.
190 llvm::yaml::Input Yin(InputContent,
191 const_cast<BenchmarkResultContext *>(&Context));
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000192 Yin >> *this;
193}
194
195// FIXME: Change the API to let the caller handle errors.
Clement Courbet53d35d22018-06-05 10:56:19 +0000196void InstructionBenchmark::writeYamlOrDie(const BenchmarkResultContext &Context,
197 const llvm::StringRef Filename) {
Clement Courbetac74acd2018-04-04 11:37:06 +0000198 if (Filename == "-") {
Clement Courbet53d35d22018-06-05 10:56:19 +0000199 writeYamlTo(Context, llvm::outs());
Clement Courbetac74acd2018-04-04 11:37:06 +0000200 } else {
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000201 int ResultFD = 0;
202 llvm::cantFail(llvm::errorCodeToError(
203 openFileForWrite(Filename, ResultFD, llvm::sys::fs::F_Text)));
204 llvm::raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/);
Clement Courbet53d35d22018-06-05 10:56:19 +0000205 writeYamlTo(Context, Ostr);
Clement Courbetac74acd2018-04-04 11:37:06 +0000206 }
207}
208
Clement Courbetae8ae5dc2018-05-24 12:41:02 +0000209void BenchmarkMeasureStats::push(const BenchmarkMeasure &BM) {
210 if (Key.empty())
211 Key = BM.Key;
212 assert(Key == BM.Key);
213 ++NumValues;
214 SumValues += BM.Value;
215 MaxValue = std::max(MaxValue, BM.Value);
216 MinValue = std::min(MinValue, BM.Value);
217}
218
Clement Courbetac74acd2018-04-04 11:37:06 +0000219} // namespace exegesis