Skip to content

[llvm-exegesis] Use explicit error classes for different snippet crashes #74210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# REQUIRES: exegesis-can-measure-latency, x86_64-linux

# RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mode=latency -snippets-file=%s -execution-mode=subprocess | FileCheck %s
# RUN: not llvm-exegesis -mtriple=x86_64-unknown-unknown -mode=latency -snippets-file=%s -execution-mode=subprocess 2>&1 | FileCheck %s

# CHECK: error: 'Child benchmarking process exited with non-zero exit code: Child process returned with unknown exit code'
# CHECK: llvm-exegesis error: Child benchmarking process exited with non-zero exit code: Child process returned with unknown exit code

movl $60, %eax
movl $127, %edi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mode=latency -snippets-file=%s -execution-mode=subprocess | FileCheck %s

# CHECK: error: 'The benchmarking subprocess sent unexpected signal: Segmentation fault'
# CHECK: error: The snippet encountered a segmentation fault at address 10

# LLVM-EXEGESIS-DEFREG RBX 0
# LLVM-EXEGESIS-DEFREG RBX 10
movq (%rbx), %rax
23 changes: 12 additions & 11 deletions llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,17 +147,16 @@ class InProcessFunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
CrashRecoveryContext::Disable();
PS.reset();
if (Crashed) {
std::string Msg = "snippet crashed while running";
#ifdef LLVM_ON_UNIX
// See "Exit Status for Commands":
// https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html
constexpr const int kSigOffset = 128;
if (const char *const SigName = strsignal(CRC.RetCode - kSigOffset)) {
Msg += ": ";
Msg += SigName;
}
#endif
return make_error<SnippetCrash>(std::move(Msg));
return make_error<SnippetSignal>(CRC.RetCode - kSigOffset);
#else
// The exit code of the process on windows is not meaningful as a
// signal, so simply pass in -1 as the signal into the error.
return make_error<SnippetSignal>(-1);
#endif // LLVM_ON_UNIX
}
}

Expand Down Expand Up @@ -366,7 +365,7 @@ class SubProcessFunctionExecutorImpl
return Error::success();
}
// The child exited, but not successfully
return make_error<SnippetCrash>(
return make_error<Failure>(
"Child benchmarking process exited with non-zero exit code: " +
childProcessExitCodeToString(ChildExitCode));
}
Expand All @@ -379,9 +378,11 @@ class SubProcessFunctionExecutorImpl
Twine(strerror(errno)));
}

return make_error<SnippetCrash>(
"The benchmarking subprocess sent unexpected signal: " +
Twine(strsignal(ChildSignalInfo.si_signo)));
if (ChildSignalInfo.si_signo == SIGSEGV)
return make_error<SnippetSegmentationFault>(
reinterpret_cast<intptr_t>(ChildSignalInfo.si_addr));

return make_error<SnippetSignal>(ChildSignalInfo.si_signo);
}

void disableCoreDumps() const {
Expand Down
26 changes: 22 additions & 4 deletions llvm/tools/llvm-exegesis/lib/Error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

#include "Error.h"

#ifdef LLVM_ON_UNIX
#include <string.h>
#endif // LLVM_ON_UNIX

namespace llvm {
namespace exegesis {

Expand All @@ -19,13 +23,27 @@ std::error_code ClusteringError::convertToErrorCode() const {
return inconvertibleErrorCode();
}

char SnippetCrash::ID;

void SnippetCrash::log(raw_ostream &OS) const { OS << Msg; }
char SnippetExecutionFailure::ID;

std::error_code SnippetCrash::convertToErrorCode() const {
std::error_code SnippetExecutionFailure::convertToErrorCode() const {
return inconvertibleErrorCode();
}

char SnippetSegmentationFault::ID;

void SnippetSegmentationFault::log(raw_ostream &OS) const {
OS << "The snippet encountered a segmentation fault at address "
<< Twine::utohexstr(Address);
}

char SnippetSignal::ID;

void SnippetSignal::log(raw_ostream &OS) const {
OS << "snippet crashed while running";
#ifdef LLVM_ON_UNIX
OS << ": " << strsignal(SignalNumber);
#endif // LLVM_ON_UNIX
}

} // namespace exegesis
} // namespace llvm
37 changes: 31 additions & 6 deletions llvm/tools/llvm-exegesis/lib/Error.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,44 @@ class ClusteringError : public ErrorInfo<ClusteringError> {
std::string Msg;
};

// A class representing failures that happened during snippet execution.
// Instead of terminating the program crashes are logged into the output.
class SnippetCrash : public ErrorInfo<SnippetCrash> {
// A class representing a non-descript snippet execution failure. This class
// is designed to sub-classed into more specific failures that contain
// additional data about the specific error that they represent. Instead of
// halting the program, the errors are reported in the output.
class SnippetExecutionFailure : public ErrorInfo<SnippetExecutionFailure> {
public:
static char ID;
SnippetCrash(const Twine &S) : Msg(S.str()) {}

std::error_code convertToErrorCode() const override;
};

// A class representing specifically segmentation faults that happen during
// snippet execution.
class SnippetSegmentationFault : public SnippetExecutionFailure {
public:
static char ID;
SnippetSegmentationFault(intptr_t SegFaultAddress)
: Address(SegFaultAddress){};

intptr_t getAddress() { return Address; }

void log(raw_ostream &OS) const override;

std::error_code convertToErrorCode() const override;
private:
intptr_t Address;
};

// A class representing all other non-specific failures that happen during
// snippet execution.
class SnippetSignal : public SnippetExecutionFailure {
public:
static char ID;
SnippetSignal(int Signal) : SignalNumber(Signal){};

void log(raw_ostream &OS) const override;

private:
std::string Msg;
int SignalNumber;
};

} // namespace exegesis
Expand Down
2 changes: 1 addition & 1 deletion llvm/tools/llvm-exegesis/llvm-exegesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ static void runBenchmarkConfigurations(
if (Err) {
// Errors from executing the snippets are fine.
// All other errors are a framework issue and should fail.
if (!Err.isA<SnippetCrash>()) {
if (!Err.isA<SnippetExecutionFailure>()) {
llvm::errs() << "llvm-exegesis error: " << toString(std::move(Err));
exit(1);
}
Expand Down