//===-- BenchmarkResult.cpp -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "BenchmarkResult.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" // Defining YAML traits for IO. namespace llvm { namespace yaml { // std::vector will be rendered as a list. template <> struct SequenceElementTraits { static const bool flow = false; }; template <> struct ScalarTraits { static void output(const llvm::MCInst &Value, void *Ctx, llvm::raw_ostream &Out) { assert(Ctx); auto *Context = static_cast(Ctx); const StringRef Name = Context->getInstrName(Value.getOpcode()); assert(!Name.empty()); Out << Name; } static StringRef input(StringRef Scalar, void *Ctx, llvm::MCInst &Value) { assert(Ctx); auto *Context = static_cast(Ctx); const unsigned Opcode = Context->getInstrOpcode(Scalar); if (Opcode == 0) { return "Unable to parse instruction"; } Value.setOpcode(Opcode); return StringRef(); } static QuotingType mustQuote(StringRef) { return QuotingType::Single; } static const bool flow = true; }; // std::vector will be rendered as a list. template <> struct SequenceElementTraits { static const bool flow = false; }; // exegesis::Measure is rendererd as a flow instead of a list. // e.g. { "key": "the key", "value": 0123 } template <> struct MappingTraits { static void mapping(IO &Io, exegesis::BenchmarkMeasure &Obj) { Io.mapRequired("key", Obj.Key); Io.mapRequired("value", Obj.Value); Io.mapOptional("debug_string", Obj.DebugString); } static const bool flow = true; }; template <> struct ScalarEnumerationTraits { static void enumeration(IO &Io, exegesis::InstructionBenchmarkKey::ModeE &Value) { Io.enumCase(Value, "", exegesis::InstructionBenchmarkKey::Unknown); Io.enumCase(Value, "latency", exegesis::InstructionBenchmarkKey::Latency); Io.enumCase(Value, "uops", exegesis::InstructionBenchmarkKey::Uops); } }; template <> struct MappingTraits { static void mapping(IO &Io, exegesis::InstructionBenchmarkKey &Obj) { Io.mapRequired("opcode_name", Obj.OpcodeName); Io.mapOptional("instructions", Obj.Instructions); Io.mapRequired("mode", Obj.Mode); Io.mapOptional("config", Obj.Config); } }; template <> struct MappingTraits { static void mapping(IO &Io, exegesis::InstructionBenchmark &Obj) { Io.mapRequired("key", Obj.Key); Io.mapRequired("cpu_name", Obj.CpuName); Io.mapRequired("llvm_triple", Obj.LLVMTriple); Io.mapRequired("num_repetitions", Obj.NumRepetitions); Io.mapRequired("measurements", Obj.Measurements); Io.mapRequired("error", Obj.Error); Io.mapOptional("info", Obj.Info); } }; } // namespace yaml } // namespace llvm LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(exegesis::InstructionBenchmark) namespace exegesis { void BenchmarkResultContext::addRegEntry(unsigned RegNo, llvm::StringRef Name) { assert(RegNoToName.find(RegNo) == RegNoToName.end()); assert(RegNameToNo.find(Name) == RegNameToNo.end()); RegNoToName[RegNo] = Name; RegNameToNo[Name] = RegNo; } llvm::StringRef BenchmarkResultContext::getRegName(unsigned RegNo) const { const auto Itr = RegNoToName.find(RegNo); if (Itr != RegNoToName.end()) return Itr->second; return {}; } unsigned BenchmarkResultContext::getRegNo(llvm::StringRef Name) const { const auto Itr = RegNameToNo.find(Name); if (Itr != RegNameToNo.end()) return Itr->second; return 0; } void BenchmarkResultContext::addInstrEntry(unsigned Opcode, llvm::StringRef Name) { assert(InstrOpcodeToName.find(Opcode) == InstrOpcodeToName.end()); assert(InstrNameToOpcode.find(Name) == InstrNameToOpcode.end()); InstrOpcodeToName[Opcode] = Name; InstrNameToOpcode[Name] = Opcode; } llvm::StringRef BenchmarkResultContext::getInstrName(unsigned Opcode) const { const auto Itr = InstrOpcodeToName.find(Opcode); if (Itr != InstrOpcodeToName.end()) return Itr->second; return {}; } unsigned BenchmarkResultContext::getInstrOpcode(llvm::StringRef Name) const { const auto Itr = InstrNameToOpcode.find(Name); if (Itr != InstrNameToOpcode.end()) return Itr->second; return 0; } template static ObjectOrList readYamlOrDieCommon(const BenchmarkResultContext &Context, llvm::StringRef Filename) { std::unique_ptr MemBuffer = llvm::cantFail( llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename))); // YAML IO requires a mutable pointer to Context but we guarantee to not // modify it. llvm::yaml::Input Yin(*MemBuffer, const_cast(&Context)); ObjectOrList Benchmark; Yin >> Benchmark; return Benchmark; } InstructionBenchmark InstructionBenchmark::readYamlOrDie(const BenchmarkResultContext &Context, llvm::StringRef Filename) { return readYamlOrDieCommon(Context, Filename); } std::vector InstructionBenchmark::readYamlsOrDie(const BenchmarkResultContext &Context, llvm::StringRef Filename) { return readYamlOrDieCommon>(Context, Filename); } void InstructionBenchmark::writeYamlTo(const BenchmarkResultContext &Context, llvm::raw_ostream &S) { // YAML IO requires a mutable pointer to Context but we guarantee to not // modify it. llvm::yaml::Output Yout(S, const_cast(&Context)); Yout << *this; } void InstructionBenchmark::readYamlFrom(const BenchmarkResultContext &Context, llvm::StringRef InputContent) { // YAML IO requires a mutable pointer to Context but we guarantee to not // modify it. llvm::yaml::Input Yin(InputContent, const_cast(&Context)); Yin >> *this; } // FIXME: Change the API to let the caller handle errors. void InstructionBenchmark::writeYamlOrDie(const BenchmarkResultContext &Context, const llvm::StringRef Filename) { if (Filename == "-") { writeYamlTo(Context, llvm::outs()); } else { int ResultFD = 0; llvm::cantFail(llvm::errorCodeToError( openFileForWrite(Filename, ResultFD, llvm::sys::fs::F_Text))); llvm::raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/); writeYamlTo(Context, Ostr); } } void BenchmarkMeasureStats::push(const BenchmarkMeasure &BM) { if (Key.empty()) Key = BM.Key; assert(Key == BM.Key); ++NumValues; SumValues += BM.Value; MaxValue = std::max(MaxValue, BM.Value); MinValue = std::min(MinValue, BM.Value); } } // namespace exegesis