//===-- BenchmarkResult.h ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// Defines classes to represent measurements and serialize/deserialize them to // Yaml. /// //===----------------------------------------------------------------------===// #ifndef LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H #define LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstBuilder.h" #include "llvm/Support/YAMLTraits.h" #include <limits> #include <string> #include <unordered_map> #include <vector> namespace exegesis { struct BenchmarkResultContext; // Forward declaration. struct InstructionBenchmarkKey { // The LLVM opcode name. std::vector<llvm::MCInst> Instructions; // An opaque configuration, that can be used to separate several benchmarks of // the same instruction under different configurations. std::string Config; }; struct BenchmarkMeasure { std::string Key; double Value; std::string DebugString; }; // The result of an instruction benchmark. struct InstructionBenchmark { InstructionBenchmarkKey Key; enum ModeE { Unknown, Latency, Uops }; ModeE Mode; std::string CpuName; std::string LLVMTriple; // The number of instructions inside the repeated snippet. For example, if a // snippet of 3 instructions is repeated 4 times, this is 12. int NumRepetitions = 0; // Note that measurements are per instruction. std::vector<BenchmarkMeasure> Measurements; std::string Error; std::string Info; std::vector<uint8_t> AssembledSnippet; // Read functions. static llvm::Expected<InstructionBenchmark> readYaml(const BenchmarkResultContext &Context, llvm::StringRef Filename); static llvm::Expected<std::vector<InstructionBenchmark>> readYamls(const BenchmarkResultContext &Context, llvm::StringRef Filename); void readYamlFrom(const BenchmarkResultContext &Context, llvm::StringRef InputContent); // Write functions, non-const because of YAML traits. void writeYamlTo(const BenchmarkResultContext &Context, llvm::raw_ostream &S); llvm::Error writeYaml(const BenchmarkResultContext &Context, const llvm::StringRef Filename); }; //------------------------------------------------------------------------------ // Utilities to work with Benchmark measures. // A class that measures stats over benchmark measures. class BenchmarkMeasureStats { public: void push(const BenchmarkMeasure &BM); double avg() const { assert(NumValues); return SumValues / NumValues; } double min() const { return MinValue; } double max() const { return MaxValue; } const std::string &key() const { return Key; } private: std::string Key; double SumValues = 0.0; int NumValues = 0; double MaxValue = std::numeric_limits<double>::min(); double MinValue = std::numeric_limits<double>::max(); }; // This context is used when de/serializing InstructionBenchmark to guarantee // that Registers and Instructions are human readable and preserved accross // different versions of LLVM. struct BenchmarkResultContext { BenchmarkResultContext() = default; BenchmarkResultContext(BenchmarkResultContext &&) = default; BenchmarkResultContext &operator=(BenchmarkResultContext &&) = default; BenchmarkResultContext(const BenchmarkResultContext &) = delete; BenchmarkResultContext &operator=(const BenchmarkResultContext &) = delete; // Populate Registers and Instruction mapping. void addRegEntry(unsigned RegNo, llvm::StringRef Name); void addInstrEntry(unsigned Opcode, llvm::StringRef Name); // Register accessors. llvm::StringRef getRegName(unsigned RegNo) const; unsigned getRegNo(llvm::StringRef Name) const; // 0 is not found. // Instruction accessors. llvm::StringRef getInstrName(unsigned Opcode) const; unsigned getInstrOpcode(llvm::StringRef Name) const; // 0 is not found. private: // Ideally we would like to use MCRegisterInfo and MCInstrInfo but doing so // would make testing harder, instead we create a mapping that we can easily // populate. std::unordered_map<unsigned, llvm::StringRef> InstrOpcodeToName; std::unordered_map<unsigned, llvm::StringRef> RegNoToName; llvm::StringMap<unsigned> InstrNameToOpcode; llvm::StringMap<unsigned> RegNameToNo; }; } // namespace exegesis #endif // LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H