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

Aiden Grossman via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 11 19:24:44 PST 2023


https://github.com/boomanaiden154 updated https://github.com/llvm/llvm-project/pull/74210

>From cea1b1c9da70d5201f2bfcfcba31cd9d95d452c2 Mon Sep 17 00:00:00 2001
From: Aiden Grossman <agrossman154 at yahoo.com>
Date: Mon, 11 Dec 2023 00:38:50 -0800
Subject: [PATCH 1/2] [llvm-exegesis] Use explicit error classes for different
 snippet crashes

This patch switches to using explicit snippet crashes that contain more
information about the specific type of error (like the address for a
segmentation fault) that occurred. All these new error classes inherit
from SnippetExecutionFailure to allow for easily grabbing all of them in
addition to filtering for specific types using the standard LLVM error
primitives.
---
 .../latency/subprocess-abnormal-exit-code.s   |  4 +-
 .../X86/latency/subprocess-segfault.s         |  4 +-
 .../llvm-exegesis/lib/BenchmarkRunner.cpp     | 19 ++++------
 llvm/tools/llvm-exegesis/lib/Error.cpp        | 26 +++++++++++--
 llvm/tools/llvm-exegesis/lib/Error.h          | 37 ++++++++++++++++---
 llvm/tools/llvm-exegesis/llvm-exegesis.cpp    |  2 +-
 6 files changed, 65 insertions(+), 27 deletions(-)

diff --git a/llvm/test/tools/llvm-exegesis/X86/latency/subprocess-abnormal-exit-code.s b/llvm/test/tools/llvm-exegesis/X86/latency/subprocess-abnormal-exit-code.s
index 849f1a2e552f18..1edb263455f953 100644
--- a/llvm/test/tools/llvm-exegesis/X86/latency/subprocess-abnormal-exit-code.s
+++ b/llvm/test/tools/llvm-exegesis/X86/latency/subprocess-abnormal-exit-code.s
@@ -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
diff --git a/llvm/test/tools/llvm-exegesis/X86/latency/subprocess-segfault.s b/llvm/test/tools/llvm-exegesis/X86/latency/subprocess-segfault.s
index 92b08e1c18c62e..c72ac287d71701 100644
--- a/llvm/test/tools/llvm-exegesis/X86/latency/subprocess-segfault.s
+++ b/llvm/test/tools/llvm-exegesis/X86/latency/subprocess-segfault.s
@@ -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
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index 6c34446e8d6632..c5ffc5f1953e4d 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -147,17 +147,10 @@ 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);
       }
     }
 
@@ -366,7 +359,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));
     }
@@ -379,9 +372,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 {
diff --git a/llvm/tools/llvm-exegesis/lib/Error.cpp b/llvm/tools/llvm-exegesis/lib/Error.cpp
index 51ce41bf00bf5c..d29c4138567046 100644
--- a/llvm/tools/llvm-exegesis/lib/Error.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Error.cpp
@@ -8,6 +8,10 @@
 
 #include "Error.h"
 
+#ifdef LLVM_ON_UNIX
+#include <string.h>
+#endif // LLVM_ON_UNIX
+
 namespace llvm {
 namespace exegesis {
 
@@ -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
diff --git a/llvm/tools/llvm-exegesis/lib/Error.h b/llvm/tools/llvm-exegesis/lib/Error.h
index e5fa093e6e1256..2587c45f557434 100644
--- a/llvm/tools/llvm-exegesis/lib/Error.h
+++ b/llvm/tools/llvm-exegesis/lib/Error.h
@@ -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
diff --git a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
index 148891a18246f6..a5f8a09dcb241d 100644
--- a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
+++ b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
@@ -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);
         }

>From 3c144abdee48a5adb4757f2ec9859be2b9b8edfb Mon Sep 17 00:00:00 2001
From: Aiden Grossman <agrossman154 at yahoo.com>
Date: Mon, 11 Dec 2023 19:24:25 -0800
Subject: [PATCH 2/2] Only return signals on Unix

---
 llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index c5ffc5f1953e4d..2d396df7337f89 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -147,10 +147,16 @@ class InProcessFunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
       CrashRecoveryContext::Disable();
       PS.reset();
       if (Crashed) {
+#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;
         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
       }
     }
 



More information about the llvm-commits mailing list