xref: /netbsd-src/external/apache2/llvm/dist/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
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