Daniel Tang commited on
Commit
1459465
·
1 Parent(s): 0cae2d6

ggml : Print backtrace on uncaught C++ exceptions (ggml/1232)

Browse files

The goal is to have what users call "full logs" contain the backtrace.

This is registered upon ggml_init. Also fixes a minor fd leak on Linux.

ggml/src/CMakeLists.txt CHANGED
@@ -194,6 +194,7 @@ add_library(ggml-base
194
  ../include/ggml-opt.h
195
  ../include/gguf.h
196
  ggml.c
 
197
  ggml-alloc.c
198
  ggml-backend.cpp
199
  ggml-opt.cpp
 
194
  ../include/ggml-opt.h
195
  ../include/gguf.h
196
  ggml.c
197
+ ggml.cpp
198
  ggml-alloc.c
199
  ggml-backend.cpp
200
  ggml-opt.cpp
ggml/src/ggml-impl.h CHANGED
@@ -32,6 +32,8 @@
32
  extern "C" {
33
  #endif
34
 
 
 
35
  #ifndef MIN
36
  # define MIN(a, b) ((a) < (b) ? (a) : (b))
37
  #endif
 
32
  extern "C" {
33
  #endif
34
 
35
+ void ggml_print_backtrace(void);
36
+
37
  #ifndef MIN
38
  # define MIN(a, b) ((a) < (b) ? (a) : (b))
39
  #endif
ggml/src/ggml.c CHANGED
@@ -133,7 +133,7 @@ static void ggml_print_backtrace_symbols(void) {
133
  }
134
  #endif
135
 
136
- static void ggml_print_backtrace(void) {
137
  const char * GGML_NO_BACKTRACE = getenv("GGML_NO_BACKTRACE");
138
  if (GGML_NO_BACKTRACE) {
139
  return;
@@ -160,6 +160,10 @@ static void ggml_print_backtrace(void) {
160
  const int parent_pid = getpid();
161
  const int child_pid = fork();
162
  if (child_pid < 0) { // error
 
 
 
 
163
  return;
164
  } else if (child_pid == 0) { // child
165
  char attach[32];
@@ -167,6 +171,7 @@ static void ggml_print_backtrace(void) {
167
  #if defined(__linux__)
168
  close(lock[1]);
169
  (void) !read(lock[0], lock, 1);
 
170
  #endif
171
  // try gdb
172
  execlp("gdb", "gdb", "--batch",
@@ -216,6 +221,8 @@ void ggml_abort(const char * file, int line, const char * fmt, ...) {
216
  abort();
217
  }
218
 
 
 
219
  //
220
  // logging
221
  //
 
133
  }
134
  #endif
135
 
136
+ void ggml_print_backtrace(void) {
137
  const char * GGML_NO_BACKTRACE = getenv("GGML_NO_BACKTRACE");
138
  if (GGML_NO_BACKTRACE) {
139
  return;
 
160
  const int parent_pid = getpid();
161
  const int child_pid = fork();
162
  if (child_pid < 0) { // error
163
+ #if defined(__linux__)
164
+ close(lock[1]);
165
+ close(lock[0]);
166
+ #endif
167
  return;
168
  } else if (child_pid == 0) { // child
169
  char attach[32];
 
171
  #if defined(__linux__)
172
  close(lock[1]);
173
  (void) !read(lock[0], lock, 1);
174
+ close(lock[0]);
175
  #endif
176
  // try gdb
177
  execlp("gdb", "gdb", "--batch",
 
221
  abort();
222
  }
223
 
224
+ // ggml_print_backtrace is registered with std::set_terminate by ggml.cpp
225
+
226
  //
227
  // logging
228
  //
ggml/src/ggml.cpp ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "ggml-impl.h"
2
+
3
+ #include <cstdlib>
4
+ #include <exception>
5
+
6
+ static std::terminate_handler previous_terminate_handler;
7
+
8
+ GGML_NORETURN static void ggml_uncaught_exception() {
9
+ ggml_print_backtrace();
10
+ if (previous_terminate_handler) {
11
+ previous_terminate_handler();
12
+ }
13
+ abort(); // unreachable unless previous_terminate_handler was nullptr
14
+ }
15
+
16
+ static bool ggml_uncaught_exception_init = []{
17
+ const char * GGML_NO_BACKTRACE = getenv("GGML_NO_BACKTRACE");
18
+ if (GGML_NO_BACKTRACE) {
19
+ return false;
20
+ }
21
+ const auto prev{std::get_terminate()};
22
+ GGML_ASSERT(prev != ggml_uncaught_exception);
23
+ previous_terminate_handler = prev;
24
+ std::set_terminate(ggml_uncaught_exception);
25
+ return true;
26
+ }();