blob: 441aee0758ee72ef5edaa7dfaab79ab3e5bf610b [file] [log] [blame]
//===-- 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<llvm::MCInst> will be rendered as a list.
template <> struct SequenceElementTraits<llvm::MCInst> {
static const bool flow = false;
};
template <> struct ScalarTraits<llvm::MCInst> {
static void output(const llvm::MCInst &Value, void *Ctx,
llvm::raw_ostream &Out) {
assert(Ctx);
auto *Context = static_cast<const exegesis::BenchmarkResultContext *>(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<const exegesis::BenchmarkResultContext *>(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<exegesis::Measure> will be rendered as a list.
template <> struct SequenceElementTraits<exegesis::BenchmarkMeasure> {
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<exegesis::BenchmarkMeasure> {
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<exegesis::InstructionBenchmarkKey::ModeE> {
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<exegesis::InstructionBenchmarkKey> {
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<exegesis::InstructionBenchmark> {
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 <typename ObjectOrList>
static ObjectOrList readYamlOrDieCommon(const BenchmarkResultContext &Context,
llvm::StringRef Filename) {
std::unique_ptr<llvm::MemoryBuffer> 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<BenchmarkResultContext *>(&Context));
ObjectOrList Benchmark;
Yin >> Benchmark;
return Benchmark;
}
InstructionBenchmark
InstructionBenchmark::readYamlOrDie(const BenchmarkResultContext &Context,
llvm::StringRef Filename) {
return readYamlOrDieCommon<InstructionBenchmark>(Context, Filename);
}
std::vector<InstructionBenchmark>
InstructionBenchmark::readYamlsOrDie(const BenchmarkResultContext &Context,
llvm::StringRef Filename) {
return readYamlOrDieCommon<std::vector<InstructionBenchmark>>(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<BenchmarkResultContext *>(&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<BenchmarkResultContext *>(&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