17330f729Sjoerg //===-- BenchmarkResult.cpp -------------------------------------*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg
97330f729Sjoerg #include "BenchmarkResult.h"
107330f729Sjoerg #include "BenchmarkRunner.h"
117330f729Sjoerg #include "Error.h"
127330f729Sjoerg #include "llvm/ADT/STLExtras.h"
137330f729Sjoerg #include "llvm/ADT/ScopeExit.h"
147330f729Sjoerg #include "llvm/ADT/StringMap.h"
157330f729Sjoerg #include "llvm/ADT/StringRef.h"
167330f729Sjoerg #include "llvm/ADT/bit.h"
177330f729Sjoerg #include "llvm/ObjectYAML/YAML.h"
187330f729Sjoerg #include "llvm/Support/FileOutputBuffer.h"
197330f729Sjoerg #include "llvm/Support/FileSystem.h"
207330f729Sjoerg #include "llvm/Support/Format.h"
217330f729Sjoerg #include "llvm/Support/raw_ostream.h"
227330f729Sjoerg
237330f729Sjoerg static constexpr const char kIntegerPrefix[] = "i_0x";
247330f729Sjoerg static constexpr const char kDoublePrefix[] = "f_";
257330f729Sjoerg static constexpr const char kInvalidOperand[] = "INVALID";
267330f729Sjoerg static constexpr llvm::StringLiteral kNoRegister("%noreg");
277330f729Sjoerg
287330f729Sjoerg namespace llvm {
297330f729Sjoerg
307330f729Sjoerg namespace {
317330f729Sjoerg
327330f729Sjoerg // A mutable struct holding an LLVMState that can be passed through the
337330f729Sjoerg // serialization process to encode/decode registers and instructions.
347330f729Sjoerg struct YamlContext {
YamlContextllvm::__anon1c1817590111::YamlContext357330f729Sjoerg YamlContext(const exegesis::LLVMState &State)
367330f729Sjoerg : State(&State), ErrorStream(LastError),
377330f729Sjoerg OpcodeNameToOpcodeIdx(
387330f729Sjoerg generateOpcodeNameToOpcodeIdxMapping(State.getInstrInfo())),
397330f729Sjoerg RegNameToRegNo(generateRegNameToRegNoMapping(State.getRegInfo())) {}
407330f729Sjoerg
417330f729Sjoerg static StringMap<unsigned>
generateOpcodeNameToOpcodeIdxMappingllvm::__anon1c1817590111::YamlContext427330f729Sjoerg generateOpcodeNameToOpcodeIdxMapping(const MCInstrInfo &InstrInfo) {
437330f729Sjoerg StringMap<unsigned> Map(InstrInfo.getNumOpcodes());
447330f729Sjoerg for (unsigned I = 0, E = InstrInfo.getNumOpcodes(); I < E; ++I)
457330f729Sjoerg Map[InstrInfo.getName(I)] = I;
467330f729Sjoerg assert(Map.size() == InstrInfo.getNumOpcodes() && "Size prediction failed");
477330f729Sjoerg return Map;
487330f729Sjoerg };
497330f729Sjoerg
507330f729Sjoerg StringMap<unsigned>
generateRegNameToRegNoMappingllvm::__anon1c1817590111::YamlContext517330f729Sjoerg generateRegNameToRegNoMapping(const MCRegisterInfo &RegInfo) {
527330f729Sjoerg StringMap<unsigned> Map(RegInfo.getNumRegs());
537330f729Sjoerg // Special-case RegNo 0, which would otherwise be spelled as ''.
547330f729Sjoerg Map[kNoRegister] = 0;
557330f729Sjoerg for (unsigned I = 1, E = RegInfo.getNumRegs(); I < E; ++I)
567330f729Sjoerg Map[RegInfo.getName(I)] = I;
577330f729Sjoerg assert(Map.size() == RegInfo.getNumRegs() && "Size prediction failed");
587330f729Sjoerg return Map;
597330f729Sjoerg };
607330f729Sjoerg
serializeMCInstllvm::__anon1c1817590111::YamlContext617330f729Sjoerg void serializeMCInst(const MCInst &MCInst, raw_ostream &OS) {
627330f729Sjoerg OS << getInstrName(MCInst.getOpcode());
637330f729Sjoerg for (const auto &Op : MCInst) {
647330f729Sjoerg OS << ' ';
657330f729Sjoerg serializeMCOperand(Op, OS);
667330f729Sjoerg }
677330f729Sjoerg }
687330f729Sjoerg
deserializeMCInstllvm::__anon1c1817590111::YamlContext697330f729Sjoerg void deserializeMCInst(StringRef String, MCInst &Value) {
707330f729Sjoerg SmallVector<StringRef, 16> Pieces;
717330f729Sjoerg String.split(Pieces, " ", /* MaxSplit */ -1, /* KeepEmpty */ false);
727330f729Sjoerg if (Pieces.empty()) {
737330f729Sjoerg ErrorStream << "Unknown Instruction: '" << String << "'\n";
747330f729Sjoerg return;
757330f729Sjoerg }
767330f729Sjoerg bool ProcessOpcode = true;
777330f729Sjoerg for (StringRef Piece : Pieces) {
787330f729Sjoerg if (ProcessOpcode)
797330f729Sjoerg Value.setOpcode(getInstrOpcode(Piece));
807330f729Sjoerg else
817330f729Sjoerg Value.addOperand(deserializeMCOperand(Piece));
827330f729Sjoerg ProcessOpcode = false;
837330f729Sjoerg }
847330f729Sjoerg }
857330f729Sjoerg
getLastErrorllvm::__anon1c1817590111::YamlContext867330f729Sjoerg std::string &getLastError() { return ErrorStream.str(); }
877330f729Sjoerg
getErrorStreamllvm::__anon1c1817590111::YamlContext887330f729Sjoerg raw_string_ostream &getErrorStream() { return ErrorStream; }
897330f729Sjoerg
getRegNamellvm::__anon1c1817590111::YamlContext907330f729Sjoerg StringRef getRegName(unsigned RegNo) {
917330f729Sjoerg // Special case: RegNo 0 is NoRegister. We have to deal with it explicitly.
927330f729Sjoerg if (RegNo == 0)
937330f729Sjoerg return kNoRegister;
947330f729Sjoerg const StringRef RegName = State->getRegInfo().getName(RegNo);
957330f729Sjoerg if (RegName.empty())
967330f729Sjoerg ErrorStream << "No register with enum value '" << RegNo << "'\n";
977330f729Sjoerg return RegName;
987330f729Sjoerg }
997330f729Sjoerg
getRegNollvm::__anon1c1817590111::YamlContext1007330f729Sjoerg Optional<unsigned> getRegNo(StringRef RegName) {
1017330f729Sjoerg auto Iter = RegNameToRegNo.find(RegName);
1027330f729Sjoerg if (Iter != RegNameToRegNo.end())
1037330f729Sjoerg return Iter->second;
1047330f729Sjoerg ErrorStream << "No register with name '" << RegName << "'\n";
1057330f729Sjoerg return None;
1067330f729Sjoerg }
1077330f729Sjoerg
1087330f729Sjoerg private:
serializeIntegerOperandllvm::__anon1c1817590111::YamlContext1097330f729Sjoerg void serializeIntegerOperand(raw_ostream &OS, int64_t Value) {
1107330f729Sjoerg OS << kIntegerPrefix;
1117330f729Sjoerg OS.write_hex(bit_cast<uint64_t>(Value));
1127330f729Sjoerg }
1137330f729Sjoerg
tryDeserializeIntegerOperandllvm::__anon1c1817590111::YamlContext1147330f729Sjoerg bool tryDeserializeIntegerOperand(StringRef String, int64_t &Value) {
1157330f729Sjoerg if (!String.consume_front(kIntegerPrefix))
1167330f729Sjoerg return false;
1177330f729Sjoerg return !String.consumeInteger(16, Value);
1187330f729Sjoerg }
1197330f729Sjoerg
serializeFPOperandllvm::__anon1c1817590111::YamlContext1207330f729Sjoerg void serializeFPOperand(raw_ostream &OS, double Value) {
1217330f729Sjoerg OS << kDoublePrefix << format("%la", Value);
1227330f729Sjoerg }
1237330f729Sjoerg
tryDeserializeFPOperandllvm::__anon1c1817590111::YamlContext1247330f729Sjoerg bool tryDeserializeFPOperand(StringRef String, double &Value) {
1257330f729Sjoerg if (!String.consume_front(kDoublePrefix))
1267330f729Sjoerg return false;
1277330f729Sjoerg char *EndPointer = nullptr;
1287330f729Sjoerg Value = strtod(String.begin(), &EndPointer);
1297330f729Sjoerg return EndPointer == String.end();
1307330f729Sjoerg }
1317330f729Sjoerg
serializeMCOperandllvm::__anon1c1817590111::YamlContext1327330f729Sjoerg void serializeMCOperand(const MCOperand &MCOperand, raw_ostream &OS) {
1337330f729Sjoerg if (MCOperand.isReg()) {
1347330f729Sjoerg OS << getRegName(MCOperand.getReg());
1357330f729Sjoerg } else if (MCOperand.isImm()) {
1367330f729Sjoerg serializeIntegerOperand(OS, MCOperand.getImm());
137*82d56013Sjoerg } else if (MCOperand.isDFPImm()) {
138*82d56013Sjoerg serializeFPOperand(OS, bit_cast<double>(MCOperand.getDFPImm()));
1397330f729Sjoerg } else {
1407330f729Sjoerg OS << kInvalidOperand;
1417330f729Sjoerg }
1427330f729Sjoerg }
1437330f729Sjoerg
deserializeMCOperandllvm::__anon1c1817590111::YamlContext1447330f729Sjoerg MCOperand deserializeMCOperand(StringRef String) {
1457330f729Sjoerg assert(!String.empty());
1467330f729Sjoerg int64_t IntValue = 0;
1477330f729Sjoerg double DoubleValue = 0;
1487330f729Sjoerg if (tryDeserializeIntegerOperand(String, IntValue))
1497330f729Sjoerg return MCOperand::createImm(IntValue);
1507330f729Sjoerg if (tryDeserializeFPOperand(String, DoubleValue))
151*82d56013Sjoerg return MCOperand::createDFPImm(bit_cast<uint64_t>(DoubleValue));
1527330f729Sjoerg if (auto RegNo = getRegNo(String))
1537330f729Sjoerg return MCOperand::createReg(*RegNo);
1547330f729Sjoerg if (String != kInvalidOperand)
1557330f729Sjoerg ErrorStream << "Unknown Operand: '" << String << "'\n";
1567330f729Sjoerg return {};
1577330f729Sjoerg }
1587330f729Sjoerg
getInstrNamellvm::__anon1c1817590111::YamlContext1597330f729Sjoerg StringRef getInstrName(unsigned InstrNo) {
1607330f729Sjoerg const StringRef InstrName = State->getInstrInfo().getName(InstrNo);
1617330f729Sjoerg if (InstrName.empty())
1627330f729Sjoerg ErrorStream << "No opcode with enum value '" << InstrNo << "'\n";
1637330f729Sjoerg return InstrName;
1647330f729Sjoerg }
1657330f729Sjoerg
getInstrOpcodellvm::__anon1c1817590111::YamlContext1667330f729Sjoerg unsigned getInstrOpcode(StringRef InstrName) {
1677330f729Sjoerg auto Iter = OpcodeNameToOpcodeIdx.find(InstrName);
1687330f729Sjoerg if (Iter != OpcodeNameToOpcodeIdx.end())
1697330f729Sjoerg return Iter->second;
1707330f729Sjoerg ErrorStream << "No opcode with name '" << InstrName << "'\n";
1717330f729Sjoerg return 0;
1727330f729Sjoerg }
1737330f729Sjoerg
1747330f729Sjoerg const exegesis::LLVMState *State;
1757330f729Sjoerg std::string LastError;
1767330f729Sjoerg raw_string_ostream ErrorStream;
1777330f729Sjoerg const StringMap<unsigned> OpcodeNameToOpcodeIdx;
1787330f729Sjoerg const StringMap<unsigned> RegNameToRegNo;
1797330f729Sjoerg };
1807330f729Sjoerg } // namespace
1817330f729Sjoerg
1827330f729Sjoerg // Defining YAML traits for IO.
1837330f729Sjoerg namespace yaml {
1847330f729Sjoerg
getTypedContext(void * Ctx)1857330f729Sjoerg static YamlContext &getTypedContext(void *Ctx) {
1867330f729Sjoerg return *reinterpret_cast<YamlContext *>(Ctx);
1877330f729Sjoerg }
1887330f729Sjoerg
1897330f729Sjoerg // std::vector<MCInst> will be rendered as a list.
1907330f729Sjoerg template <> struct SequenceElementTraits<MCInst> {
1917330f729Sjoerg static const bool flow = false;
1927330f729Sjoerg };
1937330f729Sjoerg
1947330f729Sjoerg template <> struct ScalarTraits<MCInst> {
1957330f729Sjoerg
outputllvm::yaml::ScalarTraits1967330f729Sjoerg static void output(const MCInst &Value, void *Ctx, raw_ostream &Out) {
1977330f729Sjoerg getTypedContext(Ctx).serializeMCInst(Value, Out);
1987330f729Sjoerg }
1997330f729Sjoerg
inputllvm::yaml::ScalarTraits2007330f729Sjoerg static StringRef input(StringRef Scalar, void *Ctx, MCInst &Value) {
2017330f729Sjoerg YamlContext &Context = getTypedContext(Ctx);
2027330f729Sjoerg Context.deserializeMCInst(Scalar, Value);
2037330f729Sjoerg return Context.getLastError();
2047330f729Sjoerg }
2057330f729Sjoerg
2067330f729Sjoerg // By default strings are quoted only when necessary.
2077330f729Sjoerg // We force the use of single quotes for uniformity.
mustQuotellvm::yaml::ScalarTraits2087330f729Sjoerg static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
2097330f729Sjoerg
2107330f729Sjoerg static const bool flow = true;
2117330f729Sjoerg };
2127330f729Sjoerg
2137330f729Sjoerg // std::vector<exegesis::Measure> will be rendered as a list.
2147330f729Sjoerg template <> struct SequenceElementTraits<exegesis::BenchmarkMeasure> {
2157330f729Sjoerg static const bool flow = false;
2167330f729Sjoerg };
2177330f729Sjoerg
2187330f729Sjoerg // exegesis::Measure is rendererd as a flow instead of a list.
2197330f729Sjoerg // e.g. { "key": "the key", "value": 0123 }
2207330f729Sjoerg template <> struct MappingTraits<exegesis::BenchmarkMeasure> {
mappingllvm::yaml::MappingTraits2217330f729Sjoerg static void mapping(IO &Io, exegesis::BenchmarkMeasure &Obj) {
2227330f729Sjoerg Io.mapRequired("key", Obj.Key);
2237330f729Sjoerg if (!Io.outputting()) {
2247330f729Sjoerg // For backward compatibility, interpret debug_string as a key.
2257330f729Sjoerg Io.mapOptional("debug_string", Obj.Key);
2267330f729Sjoerg }
2277330f729Sjoerg Io.mapRequired("value", Obj.PerInstructionValue);
2287330f729Sjoerg Io.mapOptional("per_snippet_value", Obj.PerSnippetValue);
2297330f729Sjoerg }
2307330f729Sjoerg static const bool flow = true;
2317330f729Sjoerg };
2327330f729Sjoerg
2337330f729Sjoerg template <>
2347330f729Sjoerg struct ScalarEnumerationTraits<exegesis::InstructionBenchmark::ModeE> {
enumerationllvm::yaml::ScalarEnumerationTraits2357330f729Sjoerg static void enumeration(IO &Io,
2367330f729Sjoerg exegesis::InstructionBenchmark::ModeE &Value) {
2377330f729Sjoerg Io.enumCase(Value, "", exegesis::InstructionBenchmark::Unknown);
2387330f729Sjoerg Io.enumCase(Value, "latency", exegesis::InstructionBenchmark::Latency);
2397330f729Sjoerg Io.enumCase(Value, "uops", exegesis::InstructionBenchmark::Uops);
2407330f729Sjoerg Io.enumCase(Value, "inverse_throughput",
2417330f729Sjoerg exegesis::InstructionBenchmark::InverseThroughput);
2427330f729Sjoerg }
2437330f729Sjoerg };
2447330f729Sjoerg
2457330f729Sjoerg // std::vector<exegesis::RegisterValue> will be rendered as a list.
2467330f729Sjoerg template <> struct SequenceElementTraits<exegesis::RegisterValue> {
2477330f729Sjoerg static const bool flow = false;
2487330f729Sjoerg };
2497330f729Sjoerg
2507330f729Sjoerg template <> struct ScalarTraits<exegesis::RegisterValue> {
2517330f729Sjoerg static constexpr const unsigned kRadix = 16;
2527330f729Sjoerg static constexpr const bool kSigned = false;
2537330f729Sjoerg
outputllvm::yaml::ScalarTraits2547330f729Sjoerg static void output(const exegesis::RegisterValue &RV, void *Ctx,
2557330f729Sjoerg raw_ostream &Out) {
2567330f729Sjoerg YamlContext &Context = getTypedContext(Ctx);
2577330f729Sjoerg Out << Context.getRegName(RV.Register) << "=0x"
2587330f729Sjoerg << RV.Value.toString(kRadix, kSigned);
2597330f729Sjoerg }
2607330f729Sjoerg
inputllvm::yaml::ScalarTraits2617330f729Sjoerg static StringRef input(StringRef String, void *Ctx,
2627330f729Sjoerg exegesis::RegisterValue &RV) {
2637330f729Sjoerg SmallVector<StringRef, 2> Pieces;
2647330f729Sjoerg String.split(Pieces, "=0x", /* MaxSplit */ -1,
2657330f729Sjoerg /* KeepEmpty */ false);
2667330f729Sjoerg YamlContext &Context = getTypedContext(Ctx);
2677330f729Sjoerg Optional<unsigned> RegNo;
2687330f729Sjoerg if (Pieces.size() == 2 && (RegNo = Context.getRegNo(Pieces[0]))) {
2697330f729Sjoerg RV.Register = *RegNo;
2707330f729Sjoerg const unsigned BitsNeeded = APInt::getBitsNeeded(Pieces[1], kRadix);
2717330f729Sjoerg RV.Value = APInt(BitsNeeded, Pieces[1], kRadix);
2727330f729Sjoerg } else {
2737330f729Sjoerg Context.getErrorStream()
2747330f729Sjoerg << "Unknown initial register value: '" << String << "'";
2757330f729Sjoerg }
2767330f729Sjoerg return Context.getLastError();
2777330f729Sjoerg }
2787330f729Sjoerg
mustQuotellvm::yaml::ScalarTraits2797330f729Sjoerg static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
2807330f729Sjoerg
2817330f729Sjoerg static const bool flow = true;
2827330f729Sjoerg };
2837330f729Sjoerg
2847330f729Sjoerg template <>
2857330f729Sjoerg struct MappingContextTraits<exegesis::InstructionBenchmarkKey, YamlContext> {
mappingllvm::yaml::MappingContextTraits2867330f729Sjoerg static void mapping(IO &Io, exegesis::InstructionBenchmarkKey &Obj,
2877330f729Sjoerg YamlContext &Context) {
2887330f729Sjoerg Io.setContext(&Context);
2897330f729Sjoerg Io.mapRequired("instructions", Obj.Instructions);
2907330f729Sjoerg Io.mapOptional("config", Obj.Config);
2917330f729Sjoerg Io.mapRequired("register_initial_values", Obj.RegisterInitialValues);
2927330f729Sjoerg }
2937330f729Sjoerg };
2947330f729Sjoerg
2957330f729Sjoerg template <>
2967330f729Sjoerg struct MappingContextTraits<exegesis::InstructionBenchmark, YamlContext> {
2977330f729Sjoerg struct NormalizedBinary {
NormalizedBinaryllvm::yaml::MappingContextTraits::NormalizedBinary2987330f729Sjoerg NormalizedBinary(IO &io) {}
NormalizedBinaryllvm::yaml::MappingContextTraits::NormalizedBinary2997330f729Sjoerg NormalizedBinary(IO &, std::vector<uint8_t> &Data) : Binary(Data) {}
denormalizellvm::yaml::MappingContextTraits::NormalizedBinary3007330f729Sjoerg std::vector<uint8_t> denormalize(IO &) {
3017330f729Sjoerg std::vector<uint8_t> Data;
3027330f729Sjoerg std::string Str;
3037330f729Sjoerg raw_string_ostream OSS(Str);
3047330f729Sjoerg Binary.writeAsBinary(OSS);
3057330f729Sjoerg OSS.flush();
3067330f729Sjoerg Data.assign(Str.begin(), Str.end());
3077330f729Sjoerg return Data;
3087330f729Sjoerg }
3097330f729Sjoerg
3107330f729Sjoerg BinaryRef Binary;
3117330f729Sjoerg };
3127330f729Sjoerg
mappingllvm::yaml::MappingContextTraits3137330f729Sjoerg static void mapping(IO &Io, exegesis::InstructionBenchmark &Obj,
3147330f729Sjoerg YamlContext &Context) {
3157330f729Sjoerg Io.mapRequired("mode", Obj.Mode);
3167330f729Sjoerg Io.mapRequired("key", Obj.Key, Context);
3177330f729Sjoerg Io.mapRequired("cpu_name", Obj.CpuName);
3187330f729Sjoerg Io.mapRequired("llvm_triple", Obj.LLVMTriple);
3197330f729Sjoerg Io.mapRequired("num_repetitions", Obj.NumRepetitions);
3207330f729Sjoerg Io.mapRequired("measurements", Obj.Measurements);
3217330f729Sjoerg Io.mapRequired("error", Obj.Error);
3227330f729Sjoerg Io.mapOptional("info", Obj.Info);
3237330f729Sjoerg // AssembledSnippet
3247330f729Sjoerg MappingNormalization<NormalizedBinary, std::vector<uint8_t>> BinaryString(
3257330f729Sjoerg Io, Obj.AssembledSnippet);
3267330f729Sjoerg Io.mapOptional("assembled_snippet", BinaryString->Binary);
3277330f729Sjoerg }
3287330f729Sjoerg };
3297330f729Sjoerg
3307330f729Sjoerg } // namespace yaml
3317330f729Sjoerg
3327330f729Sjoerg namespace exegesis {
3337330f729Sjoerg
3347330f729Sjoerg Expected<InstructionBenchmark>
readYaml(const LLVMState & State,StringRef Filename)3357330f729Sjoerg InstructionBenchmark::readYaml(const LLVMState &State, StringRef Filename) {
3367330f729Sjoerg if (auto ExpectedMemoryBuffer =
337*82d56013Sjoerg errorOrToExpected(MemoryBuffer::getFile(Filename, /*IsText=*/true))) {
3387330f729Sjoerg yaml::Input Yin(*ExpectedMemoryBuffer.get());
3397330f729Sjoerg YamlContext Context(State);
3407330f729Sjoerg InstructionBenchmark Benchmark;
3417330f729Sjoerg if (Yin.setCurrentDocument())
3427330f729Sjoerg yaml::yamlize(Yin, Benchmark, /*unused*/ true, Context);
3437330f729Sjoerg if (!Context.getLastError().empty())
3447330f729Sjoerg return make_error<Failure>(Context.getLastError());
3457330f729Sjoerg return Benchmark;
3467330f729Sjoerg } else {
3477330f729Sjoerg return ExpectedMemoryBuffer.takeError();
3487330f729Sjoerg }
3497330f729Sjoerg }
3507330f729Sjoerg
3517330f729Sjoerg Expected<std::vector<InstructionBenchmark>>
readYamls(const LLVMState & State,StringRef Filename)3527330f729Sjoerg InstructionBenchmark::readYamls(const LLVMState &State, StringRef Filename) {
3537330f729Sjoerg if (auto ExpectedMemoryBuffer =
354*82d56013Sjoerg errorOrToExpected(MemoryBuffer::getFile(Filename, /*IsText=*/true))) {
3557330f729Sjoerg yaml::Input Yin(*ExpectedMemoryBuffer.get());
3567330f729Sjoerg YamlContext Context(State);
3577330f729Sjoerg std::vector<InstructionBenchmark> Benchmarks;
3587330f729Sjoerg while (Yin.setCurrentDocument()) {
3597330f729Sjoerg Benchmarks.emplace_back();
3607330f729Sjoerg yamlize(Yin, Benchmarks.back(), /*unused*/ true, Context);
3617330f729Sjoerg if (Yin.error())
3627330f729Sjoerg return errorCodeToError(Yin.error());
3637330f729Sjoerg if (!Context.getLastError().empty())
3647330f729Sjoerg return make_error<Failure>(Context.getLastError());
3657330f729Sjoerg Yin.nextDocument();
3667330f729Sjoerg }
3677330f729Sjoerg return Benchmarks;
3687330f729Sjoerg } else {
3697330f729Sjoerg return ExpectedMemoryBuffer.takeError();
3707330f729Sjoerg }
3717330f729Sjoerg }
3727330f729Sjoerg
writeYamlTo(const LLVMState & State,raw_ostream & OS)3737330f729Sjoerg Error InstructionBenchmark::writeYamlTo(const LLVMState &State,
3747330f729Sjoerg raw_ostream &OS) {
3757330f729Sjoerg auto Cleanup = make_scope_exit([&] { OS.flush(); });
3767330f729Sjoerg yaml::Output Yout(OS, nullptr /*Ctx*/, 200 /*WrapColumn*/);
3777330f729Sjoerg YamlContext Context(State);
3787330f729Sjoerg Yout.beginDocuments();
3797330f729Sjoerg yaml::yamlize(Yout, *this, /*unused*/ true, Context);
3807330f729Sjoerg if (!Context.getLastError().empty())
3817330f729Sjoerg return make_error<Failure>(Context.getLastError());
3827330f729Sjoerg Yout.endDocuments();
3837330f729Sjoerg return Error::success();
3847330f729Sjoerg }
3857330f729Sjoerg
readYamlFrom(const LLVMState & State,StringRef InputContent)3867330f729Sjoerg Error InstructionBenchmark::readYamlFrom(const LLVMState &State,
3877330f729Sjoerg StringRef InputContent) {
3887330f729Sjoerg yaml::Input Yin(InputContent);
3897330f729Sjoerg YamlContext Context(State);
3907330f729Sjoerg if (Yin.setCurrentDocument())
3917330f729Sjoerg yaml::yamlize(Yin, *this, /*unused*/ true, Context);
3927330f729Sjoerg if (!Context.getLastError().empty())
3937330f729Sjoerg return make_error<Failure>(Context.getLastError());
3947330f729Sjoerg return Error::success();
3957330f729Sjoerg }
3967330f729Sjoerg
writeYaml(const LLVMState & State,const StringRef Filename)3977330f729Sjoerg Error InstructionBenchmark::writeYaml(const LLVMState &State,
3987330f729Sjoerg const StringRef Filename) {
3997330f729Sjoerg if (Filename == "-") {
4007330f729Sjoerg if (auto Err = writeYamlTo(State, outs()))
4017330f729Sjoerg return Err;
4027330f729Sjoerg } else {
4037330f729Sjoerg int ResultFD = 0;
404*82d56013Sjoerg if (auto E = errorCodeToError(openFileForWrite(Filename, ResultFD,
405*82d56013Sjoerg sys::fs::CD_CreateAlways,
406*82d56013Sjoerg sys::fs::OF_TextWithCRLF))) {
4077330f729Sjoerg return E;
4087330f729Sjoerg }
4097330f729Sjoerg raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/);
4107330f729Sjoerg if (auto Err = writeYamlTo(State, Ostr))
4117330f729Sjoerg return Err;
4127330f729Sjoerg }
4137330f729Sjoerg return Error::success();
4147330f729Sjoerg }
4157330f729Sjoerg
push(const BenchmarkMeasure & BM)4167330f729Sjoerg void PerInstructionStats::push(const BenchmarkMeasure &BM) {
4177330f729Sjoerg if (Key.empty())
4187330f729Sjoerg Key = BM.Key;
4197330f729Sjoerg assert(Key == BM.Key);
4207330f729Sjoerg ++NumValues;
4217330f729Sjoerg SumValues += BM.PerInstructionValue;
4227330f729Sjoerg MaxValue = std::max(MaxValue, BM.PerInstructionValue);
4237330f729Sjoerg MinValue = std::min(MinValue, BM.PerInstructionValue);
4247330f729Sjoerg }
4257330f729Sjoerg
4267330f729Sjoerg } // namespace exegesis
4277330f729Sjoerg } // namespace llvm
428