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

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.
This commit is contained in:
Daniel Tang 2025-05-27 20:58:46 -04:00 committed by Georgi Gerganov
parent 73a8c5fb94
commit 5ea2c37a4c
4 changed files with 37 additions and 1 deletions

View File

@ -194,6 +194,7 @@ add_library(ggml-base
../include/ggml-opt.h ../include/ggml-opt.h
../include/gguf.h ../include/gguf.h
ggml.c ggml.c
ggml.cpp
ggml-alloc.c ggml-alloc.c
ggml-backend.cpp ggml-backend.cpp
ggml-opt.cpp ggml-opt.cpp

View File

@ -32,6 +32,8 @@
extern "C" { extern "C" {
#endif #endif
void ggml_print_backtrace(void);
#ifndef MIN #ifndef MIN
# define MIN(a, b) ((a) < (b) ? (a) : (b)) # define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif #endif

View File

@ -133,7 +133,7 @@ static void ggml_print_backtrace_symbols(void) {
} }
#endif #endif
static void ggml_print_backtrace(void) { void ggml_print_backtrace(void) {
const char * GGML_NO_BACKTRACE = getenv("GGML_NO_BACKTRACE"); const char * GGML_NO_BACKTRACE = getenv("GGML_NO_BACKTRACE");
if (GGML_NO_BACKTRACE) { if (GGML_NO_BACKTRACE) {
return; return;
@ -160,6 +160,10 @@ static void ggml_print_backtrace(void) {
const int parent_pid = getpid(); const int parent_pid = getpid();
const int child_pid = fork(); const int child_pid = fork();
if (child_pid < 0) { // error if (child_pid < 0) { // error
#if defined(__linux__)
close(lock[1]);
close(lock[0]);
#endif
return; return;
} else if (child_pid == 0) { // child } else if (child_pid == 0) { // child
char attach[32]; char attach[32];
@ -167,6 +171,7 @@ static void ggml_print_backtrace(void) {
#if defined(__linux__) #if defined(__linux__)
close(lock[1]); close(lock[1]);
(void) !read(lock[0], lock, 1); (void) !read(lock[0], lock, 1);
close(lock[0]);
#endif #endif
// try gdb // try gdb
execlp("gdb", "gdb", "--batch", execlp("gdb", "gdb", "--batch",
@ -216,6 +221,8 @@ void ggml_abort(const char * file, int line, const char * fmt, ...) {
abort(); abort();
} }
// ggml_print_backtrace is registered with std::set_terminate by ggml.cpp
// //
// logging // logging
// //

26
ggml/src/ggml.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "ggml-impl.h"
#include <cstdlib>
#include <exception>
static std::terminate_handler previous_terminate_handler;
GGML_NORETURN static void ggml_uncaught_exception() {
ggml_print_backtrace();
if (previous_terminate_handler) {
previous_terminate_handler();
}
abort(); // unreachable unless previous_terminate_handler was nullptr
}
static bool ggml_uncaught_exception_init = []{
const char * GGML_NO_BACKTRACE = getenv("GGML_NO_BACKTRACE");
if (GGML_NO_BACKTRACE) {
return false;
}
const auto prev{std::get_terminate()};
GGML_ASSERT(prev != ggml_uncaught_exception);
previous_terminate_handler = prev;
std::set_terminate(ggml_uncaught_exception);
return true;
}();