[llvm-exegesis] Improve error reporting.

Summary: BenchmarkResult IO functions now return an Error or Expected so caller can deal take proper action.

Reviewers: courbet

Subscribers: tschuett, llvm-commits

Differential Revision: https://reviews.llvm.org/D47868

llvm-svn: 334167
This commit is contained in:
Guillaume Chatelet 2018-06-07 07:51:16 +00:00
parent 30c5e4ad35
commit 8c91d4cb04
4 changed files with 58 additions and 43 deletions

View File

@ -210,27 +210,32 @@ unsigned BenchmarkResultContext::getInstrOpcode(llvm::StringRef Name) const {
} }
template <typename ObjectOrList> template <typename ObjectOrList>
static ObjectOrList readYamlOrDieCommon(const BenchmarkResultContext &Context, static llvm::Expected<ObjectOrList>
llvm::StringRef Filename) { readYamlCommon(const BenchmarkResultContext &Context,
std::unique_ptr<llvm::MemoryBuffer> MemBuffer = llvm::cantFail( llvm::StringRef Filename) {
llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename))); if (auto ExpectedMemoryBuffer =
llvm::yaml::Input Yin(*MemBuffer, getUntypedContext(Context)); llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename))) {
ObjectOrList Benchmark; std::unique_ptr<llvm::MemoryBuffer> MemoryBuffer =
Yin >> Benchmark; std::move(ExpectedMemoryBuffer.get());
return Benchmark; llvm::yaml::Input Yin(*MemoryBuffer, getUntypedContext(Context));
ObjectOrList Benchmark;
Yin >> Benchmark;
return Benchmark;
} else {
return ExpectedMemoryBuffer.takeError();
}
} }
InstructionBenchmark llvm::Expected<InstructionBenchmark>
InstructionBenchmark::readYamlOrDie(const BenchmarkResultContext &Context, InstructionBenchmark::readYaml(const BenchmarkResultContext &Context,
llvm::StringRef Filename) { llvm::StringRef Filename) {
return readYamlOrDieCommon<InstructionBenchmark>(Context, Filename); return readYamlCommon<InstructionBenchmark>(Context, Filename);
} }
std::vector<InstructionBenchmark> llvm::Expected<std::vector<InstructionBenchmark>>
InstructionBenchmark::readYamlsOrDie(const BenchmarkResultContext &Context, InstructionBenchmark::readYamls(const BenchmarkResultContext &Context,
llvm::StringRef Filename) { llvm::StringRef Filename) {
return readYamlOrDieCommon<std::vector<InstructionBenchmark>>(Context, return readYamlCommon<std::vector<InstructionBenchmark>>(Context, Filename);
Filename);
} }
void InstructionBenchmark::writeYamlTo(const BenchmarkResultContext &Context, void InstructionBenchmark::writeYamlTo(const BenchmarkResultContext &Context,
@ -245,18 +250,21 @@ void InstructionBenchmark::readYamlFrom(const BenchmarkResultContext &Context,
Yin >> *this; Yin >> *this;
} }
// FIXME: Change the API to let the caller handle errors. llvm::Error
void InstructionBenchmark::writeYamlOrDie(const BenchmarkResultContext &Context, InstructionBenchmark::writeYaml(const BenchmarkResultContext &Context,
const llvm::StringRef Filename) { const llvm::StringRef Filename) {
if (Filename == "-") { if (Filename == "-") {
writeYamlTo(Context, llvm::outs()); writeYamlTo(Context, llvm::outs());
} else { } else {
int ResultFD = 0; int ResultFD = 0;
llvm::cantFail(llvm::errorCodeToError( if (auto E = llvm::errorCodeToError(
openFileForWrite(Filename, ResultFD, llvm::sys::fs::F_Text))); openFileForWrite(Filename, ResultFD, llvm::sys::fs::F_Text))) {
return E;
}
llvm::raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/); llvm::raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/);
writeYamlTo(Context, Ostr); writeYamlTo(Context, Ostr);
} }
return llvm::Error::success();
} }
void BenchmarkMeasureStats::push(const BenchmarkMeasure &BM) { void BenchmarkMeasureStats::push(const BenchmarkMeasure &BM) {

View File

@ -58,13 +58,11 @@ struct InstructionBenchmark {
std::string Info; std::string Info;
// Read functions. // Read functions.
static InstructionBenchmark static llvm::Expected<InstructionBenchmark>
readYamlOrDie(const BenchmarkResultContext &Context, readYaml(const BenchmarkResultContext &Context, llvm::StringRef Filename);
llvm::StringRef Filename);
static std::vector<InstructionBenchmark> static llvm::Expected<std::vector<InstructionBenchmark>>
readYamlsOrDie(const BenchmarkResultContext &Context, readYamls(const BenchmarkResultContext &Context, llvm::StringRef Filename);
llvm::StringRef Filename);
void readYamlFrom(const BenchmarkResultContext &Context, void readYamlFrom(const BenchmarkResultContext &Context,
llvm::StringRef InputContent); llvm::StringRef InputContent);
@ -72,8 +70,8 @@ struct InstructionBenchmark {
// Write functions, non-const because of YAML traits. // Write functions, non-const because of YAML traits.
void writeYamlTo(const BenchmarkResultContext &Context, llvm::raw_ostream &S); void writeYamlTo(const BenchmarkResultContext &Context, llvm::raw_ostream &S);
void writeYamlOrDie(const BenchmarkResultContext &Context, llvm::Error writeYaml(const BenchmarkResultContext &Context,
const llvm::StringRef Filename); const llvm::StringRef Filename);
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -45,7 +45,7 @@ static llvm::cl::opt<std::string>
llvm::cl::init("")); llvm::cl::init(""));
static llvm::cl::opt<std::string> static llvm::cl::opt<std::string>
BenchmarkFile("benchmarks-file", llvm::cl::desc(""), llvm::cl::init("-")); BenchmarkFile("benchmarks-file", llvm::cl::desc(""), llvm::cl::init(""));
enum class BenchmarkModeE { Latency, Uops, Analysis }; enum class BenchmarkModeE { Latency, Uops, Analysis };
static llvm::cl::opt<BenchmarkModeE> BenchmarkMode( static llvm::cl::opt<BenchmarkModeE> BenchmarkMode(
@ -79,6 +79,8 @@ static llvm::cl::opt<std::string>
namespace exegesis { namespace exegesis {
static llvm::ExitOnError ExitOnErr;
static unsigned GetOpcodeOrDie(const llvm::MCInstrInfo &MCInstrInfo) { static unsigned GetOpcodeOrDie(const llvm::MCInstrInfo &MCInstrInfo) {
if (OpcodeName.empty() && (OpcodeIndex == 0)) if (OpcodeName.empty() && (OpcodeIndex == 0))
llvm::report_fatal_error( llvm::report_fatal_error(
@ -138,8 +140,13 @@ void benchmarkMain() {
if (NumRepetitions == 0) if (NumRepetitions == 0)
llvm::report_fatal_error("--num-repetitions must be greater than zero"); llvm::report_fatal_error("--num-repetitions must be greater than zero");
Runner->run(GetOpcodeOrDie(State.getInstrInfo()), Filter, NumRepetitions) // Write to standard output if file is not set.
.writeYamlOrDie(getBenchmarkResultContext(State), BenchmarkFile); if (BenchmarkFile.empty())
BenchmarkFile = "-";
ExitOnErr(
Runner->run(GetOpcodeOrDie(State.getInstrInfo()), Filter, NumRepetitions)
.writeYaml(getBenchmarkResultContext(State), BenchmarkFile));
exegesis::pfm::pfmTerminate(); exegesis::pfm::pfmTerminate();
} }
@ -157,21 +164,21 @@ static void maybeRunAnalysis(const Analysis &Analyzer, const std::string &Name,
std::error_code ErrorCode; std::error_code ErrorCode;
llvm::raw_fd_ostream ClustersOS(OutputFilename, ErrorCode, llvm::raw_fd_ostream ClustersOS(OutputFilename, ErrorCode,
llvm::sys::fs::F_RW); llvm::sys::fs::F_RW);
if (ErrorCode) ExitOnErr(llvm::errorCodeToError(ErrorCode));
llvm::report_fatal_error("cannot open out file: " + OutputFilename); ExitOnErr(Analyzer.run<Pass>(ClustersOS));
if (auto Err = Analyzer.run<Pass>(ClustersOS))
llvm::report_fatal_error(std::move(Err));
} }
static void analysisMain() { static void analysisMain() {
if (BenchmarkFile.empty())
llvm::report_fatal_error("--benchmarks-file must be set.");
llvm::InitializeNativeTarget(); llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter(); llvm::InitializeNativeTargetAsmPrinter();
// Read benchmarks. // Read benchmarks.
const LLVMState State; const LLVMState State;
const std::vector<InstructionBenchmark> Points = const std::vector<InstructionBenchmark> Points =
InstructionBenchmark::readYamlsOrDie(getBenchmarkResultContext(State), ExitOnErr(InstructionBenchmark::readYamls(
BenchmarkFile); getBenchmarkResultContext(State), BenchmarkFile));
llvm::outs() << "Parsed " << Points.size() << " benchmark points\n"; llvm::outs() << "Parsed " << Points.size() << " benchmark points\n";
if (Points.empty()) { if (Points.empty()) {
llvm::errs() << "no benchmarks to analyze\n"; llvm::errs() << "no benchmarks to analyze\n";

View File

@ -55,6 +55,7 @@ static constexpr const unsigned kReg2Id = 2;
static constexpr const char kReg2Name[] = "Reg2"; static constexpr const char kReg2Name[] = "Reg2";
TEST(BenchmarkResultTest, WriteToAndReadFromDisk) { TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
llvm::ExitOnError ExitOnErr;
BenchmarkResultContext Ctx; BenchmarkResultContext Ctx;
Ctx.addInstrEntry(kInstrId, kInstrName); Ctx.addInstrEntry(kInstrId, kInstrName);
Ctx.addRegEntry(kReg1Id, kReg1Name); Ctx.addRegEntry(kReg1Id, kReg1Name);
@ -83,11 +84,12 @@ TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
EC = llvm::sys::fs::createUniqueDirectory("BenchmarkResultTestDir", Filename); EC = llvm::sys::fs::createUniqueDirectory("BenchmarkResultTestDir", Filename);
ASSERT_FALSE(EC); ASSERT_FALSE(EC);
llvm::sys::path::append(Filename, "data.yaml"); llvm::sys::path::append(Filename, "data.yaml");
ToDisk.writeYamlOrDie(Ctx, Filename); ExitOnErr(ToDisk.writeYaml(Ctx, Filename));
{ {
// One-element version. // One-element version.
const auto FromDisk = InstructionBenchmark::readYamlOrDie(Ctx, Filename); const auto FromDisk =
ExitOnErr(InstructionBenchmark::readYaml(Ctx, Filename));
EXPECT_EQ(FromDisk.Key.OpcodeName, ToDisk.Key.OpcodeName); EXPECT_EQ(FromDisk.Key.OpcodeName, ToDisk.Key.OpcodeName);
EXPECT_THAT(FromDisk.Key.Instructions, EXPECT_THAT(FromDisk.Key.Instructions,
@ -104,7 +106,7 @@ TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
{ {
// Vector version. // Vector version.
const auto FromDiskVector = const auto FromDiskVector =
InstructionBenchmark::readYamlsOrDie(Ctx, Filename); ExitOnErr(InstructionBenchmark::readYamls(Ctx, Filename));
ASSERT_EQ(FromDiskVector.size(), size_t{1}); ASSERT_EQ(FromDiskVector.size(), size_t{1});
const auto FromDisk = FromDiskVector[0]; const auto FromDisk = FromDiskVector[0];
EXPECT_EQ(FromDisk.Key.OpcodeName, ToDisk.Key.OpcodeName); EXPECT_EQ(FromDisk.Key.OpcodeName, ToDisk.Key.OpcodeName);