1 //===-- BenchmarkResult.cpp -------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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"
18 static constexpr const char kIntegerFormat[] = "i_0x%" PRId64 "x";
19 static constexpr const char kDoubleFormat[] = "f_%la";
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());
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) {
39 serialize(Context, Op, OS);
43 static llvm::MCOperand
44 deserialize(const exegesis::BenchmarkResultContext &Context,
45 llvm::StringRef String) {
46 assert(!String.empty());
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);
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, " ");
64 return "Invalid Instruction";
65 bool ProcessOpcode = true;
66 for (llvm::StringRef Piece : Pieces) {
68 ProcessOpcode = false;
69 Value.setOpcode(Context.getInstrOpcode(Piece));
70 if (Value.getOpcode() == 0)
71 return "Unknown Opcode Name";
73 Value.addOperand(deserialize(Context, Piece));
79 // YAML IO requires a mutable pointer to Context but we guarantee to not
81 static void *getUntypedContext(const exegesis::BenchmarkResultContext &Ctx) {
82 return const_cast<exegesis::BenchmarkResultContext *>(&Ctx);
85 static const exegesis::BenchmarkResultContext &getTypedContext(void *Ctx) {
87 return *static_cast<const exegesis::BenchmarkResultContext *>(Ctx);
90 // Defining YAML traits for IO.
94 // std::vector<llvm::MCInst> will be rendered as a list.
95 template <> struct SequenceElementTraits<llvm::MCInst> {
96 static const bool flow = false;
99 template <> struct ScalarTraits<llvm::MCInst> {
101 static void output(const llvm::MCInst &Value, void *Ctx,
102 llvm::raw_ostream &Out) {
103 serialize(getTypedContext(Ctx), Value, Out);
106 static StringRef input(StringRef Scalar, void *Ctx, llvm::MCInst &Value) {
107 return deserialize(getTypedContext(Ctx), Scalar, Value);
110 static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
112 static const bool flow = true;
115 // std::vector<exegesis::Measure> will be rendered as a list.
116 template <> struct SequenceElementTraits<exegesis::BenchmarkMeasure> {
117 static const bool flow = false;
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);
128 static const bool flow = true;
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);
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);
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);
165 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(exegesis::InstructionBenchmark)
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;
176 llvm::StringRef BenchmarkResultContext::getRegName(unsigned RegNo) const {
177 const auto Itr = RegNoToName.find(RegNo);
178 if (Itr != RegNoToName.end())
183 unsigned BenchmarkResultContext::getRegNo(llvm::StringRef Name) const {
184 const auto Itr = RegNameToNo.find(Name);
185 if (Itr != RegNameToNo.end())
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;
198 llvm::StringRef BenchmarkResultContext::getInstrName(unsigned Opcode) const {
199 const auto Itr = InstrOpcodeToName.find(Opcode);
200 if (Itr != InstrOpcodeToName.end())
205 unsigned BenchmarkResultContext::getInstrOpcode(llvm::StringRef Name) const {
206 const auto Itr = InstrNameToOpcode.find(Name);
207 if (Itr != InstrNameToOpcode.end())
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;
225 return ExpectedMemoryBuffer.takeError();
229 llvm::Expected<InstructionBenchmark>
230 InstructionBenchmark::readYaml(const BenchmarkResultContext &Context,
231 llvm::StringRef Filename) {
232 return readYamlCommon<InstructionBenchmark>(Context, Filename);
235 llvm::Expected<std::vector<InstructionBenchmark>>
236 InstructionBenchmark::readYamls(const BenchmarkResultContext &Context,
237 llvm::StringRef Filename) {
238 return readYamlCommon<std::vector<InstructionBenchmark>>(Context, Filename);
241 void InstructionBenchmark::writeYamlTo(const BenchmarkResultContext &Context,
242 llvm::raw_ostream &OS) {
243 llvm::yaml::Output Yout(OS, getUntypedContext(Context));
247 void InstructionBenchmark::readYamlFrom(const BenchmarkResultContext &Context,
248 llvm::StringRef InputContent) {
249 llvm::yaml::Input Yin(InputContent, getUntypedContext(Context));
254 InstructionBenchmark::writeYaml(const BenchmarkResultContext &Context,
255 const llvm::StringRef Filename) {
256 if (Filename == "-") {
257 writeYamlTo(Context, llvm::outs());
260 if (auto E = llvm::errorCodeToError(
261 openFileForWrite(Filename, ResultFD, llvm::sys::fs::F_Text))) {
264 llvm::raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/);
265 writeYamlTo(Context, Ostr);
267 return llvm::Error::success();
270 void BenchmarkMeasureStats::push(const BenchmarkMeasure &BM) {
273 assert(Key == BM.Key);
275 SumValues += BM.Value;
276 MaxValue = std::max(MaxValue, BM.Value);
277 MinValue = std::min(MinValue, BM.Value);
280 } // namespace exegesis