OSDN Git Service

9fe7a8463532b8ade133bb5c466dc5ba52aab5a5
[android-x86/external-llvm.git] / tools / llvm-exegesis / lib / BenchmarkResult.cpp
1 //===-- 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"
11 #include "llvm/ADT/STLExtras.h"
12 #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 static constexpr const char kIntegerFormat[] = "i_0x%" PRId64 "x";
19 static constexpr const char kDoubleFormat[] = "f_%la";
20
21 static 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
34 static 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
43 static llvm::MCOperand
44 deserialize(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
58 static llvm::StringRef
59 deserialize(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.
81 static void *getUntypedContext(const exegesis::BenchmarkResultContext &Ctx) {
82   return const_cast<exegesis::BenchmarkResultContext *>(&Ctx);
83 }
84
85 static const exegesis::BenchmarkResultContext &getTypedContext(void *Ctx) {
86   assert(Ctx);
87   return *static_cast<const exegesis::BenchmarkResultContext *>(Ctx);
88 }
89
90 // Defining YAML traits for IO.
91 namespace llvm {
92 namespace yaml {
93
94 // std::vector<llvm::MCInst> will be rendered as a list.
95 template <> struct SequenceElementTraits<llvm::MCInst> {
96   static const bool flow = false;
97 };
98
99 template <> struct ScalarTraits<llvm::MCInst> {
100
101   static void output(const llvm::MCInst &Value, void *Ctx,
102                      llvm::raw_ostream &Out) {
103     serialize(getTypedContext(Ctx), Value, Out);
104   }
105
106   static StringRef input(StringRef Scalar, void *Ctx, llvm::MCInst &Value) {
107     return deserialize(getTypedContext(Ctx), Scalar, Value);
108   }
109
110   static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
111
112   static const bool flow = true;
113 };
114
115 // std::vector<exegesis::Measure> will be rendered as a list.
116 template <> 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 }
122 template <> 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
131 template <>
132 struct ScalarEnumerationTraits<exegesis::InstructionBenchmark::ModeE> {
133   static void enumeration(IO &Io,
134                           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);
138   }
139 };
140
141 template <> struct MappingTraits<exegesis::InstructionBenchmarkKey> {
142   static void mapping(IO &Io, exegesis::InstructionBenchmarkKey &Obj) {
143     Io.mapRequired("opcode_name", Obj.OpcodeName);
144     Io.mapOptional("instructions", Obj.Instructions);
145     Io.mapOptional("config", Obj.Config);
146   }
147 };
148
149 template <> struct MappingTraits<exegesis::InstructionBenchmark> {
150   static void mapping(IO &Io, exegesis::InstructionBenchmark &Obj) {
151     Io.mapRequired("mode", Obj.Mode);
152     Io.mapRequired("key", Obj.Key);
153     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);
158     Io.mapOptional("info", Obj.Info);
159   }
160 };
161
162 } // namespace yaml
163 } // namespace llvm
164
165 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(exegesis::InstructionBenchmark)
166
167 namespace exegesis {
168
169 void 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
176 llvm::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
183 unsigned 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
190 void 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
198 llvm::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
205 unsigned 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
212 template <typename ObjectOrList>
213 static llvm::Expected<ObjectOrList>
214 readYamlCommon(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   }
227 }
228
229 llvm::Expected<InstructionBenchmark>
230 InstructionBenchmark::readYaml(const BenchmarkResultContext &Context,
231                                llvm::StringRef Filename) {
232   return readYamlCommon<InstructionBenchmark>(Context, Filename);
233 }
234
235 llvm::Expected<std::vector<InstructionBenchmark>>
236 InstructionBenchmark::readYamls(const BenchmarkResultContext &Context,
237                                 llvm::StringRef Filename) {
238   return readYamlCommon<std::vector<InstructionBenchmark>>(Context, Filename);
239 }
240
241 void InstructionBenchmark::writeYamlTo(const BenchmarkResultContext &Context,
242                                        llvm::raw_ostream &OS) {
243   llvm::yaml::Output Yout(OS, getUntypedContext(Context));
244   Yout << *this;
245 }
246
247 void InstructionBenchmark::readYamlFrom(const BenchmarkResultContext &Context,
248                                         llvm::StringRef InputContent) {
249   llvm::yaml::Input Yin(InputContent, getUntypedContext(Context));
250   Yin >> *this;
251 }
252
253 llvm::Error
254 InstructionBenchmark::writeYaml(const BenchmarkResultContext &Context,
255                                 const llvm::StringRef Filename) {
256   if (Filename == "-") {
257     writeYamlTo(Context, llvm::outs());
258   } else {
259     int ResultFD = 0;
260     if (auto E = llvm::errorCodeToError(
261             openFileForWrite(Filename, ResultFD, llvm::sys::fs::F_Text))) {
262       return E;
263     }
264     llvm::raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/);
265     writeYamlTo(Context, Ostr);
266   }
267   return llvm::Error::success();
268 }
269
270 void 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
280 } // namespace exegesis