From 4f5623889c14b1fadd6e9f9e8d75d2e4bd9915db Mon Sep 17 00:00:00 2001 From: "Artem M. Chirkin" <9253178+achirkin@users.noreply.github.com> Date: Thu, 15 Feb 2024 23:10:58 +0100 Subject: [PATCH] Demangle backtrace symbols on raft error (#2188) Demangle the error stack trace provided by GCC. Example output: ```bash RAFT failure at file=/workspace/raft/cpp/bench/ann/src/raft/raft_ann_bench_utils.h line=127: Ooops! Obtained 16 stack frames #1 in /workspace/raft/cpp/build/libraft_ivf_pq_ann_bench.so: raft::logic_error::logic_error(std::__cxx11::basic_string, std::allocator > const&) +0x5e [0x7fb20acce45e] #2 in /workspace/raft/cpp/build/libraft_ivf_pq_ann_bench.so: raft::bench::ann::configured_raft_resources::stream_wait(CUstream_st*) const +0x2e3 [0x7fb20acd0ac3] #3 in /workspace/raft/cpp/build/libraft_ivf_pq_ann_bench.so: raft::bench::ann::RaftIvfPQ::search(float const*, int, int, unsigned long*, float*, CUstream_st*) const +0x63e [0x7fb20acd44fe] #4 in ./cpp/build/ANN_BENCH: void raft::bench::ann::bench_search(benchmark::State&, raft::bench::ann::Configuration::Index, unsigned long, std::shared_ptr const>, raft::bench::ann::Objective) +0xf76 [0x55853859f586] #5 in ./cpp/build/ANN_BENCH: benchmark::internal::LambdaBenchmark const>, raft::bench::ann::Objective), raft::bench::ann::Configuration::Index&, unsigned long&, std::shared_ptr const>&, raft::bench::ann::Objective&>(std::__cxx11::basic_string, std::allocator > const&, void (&)(benchmark::State&, raft::bench::ann::Configuration::Index, unsigned long, std::shared_ptr const>, raft::bench::ann::Objective), raft::bench::ann::Configuration::Index&, unsigned long&, std::shared_ptr const>&, raft::bench::ann::Objective&)::{lambda(benchmark::State&)#1}>::Run(benchmark::State&) +0x84 [0x558538548f14] #6 in ./cpp/build/ANN_BENCH: benchmark::internal::BenchmarkInstance::Run(long, int, benchmark::internal::ThreadTimer*, benchmark::internal::ThreadManager*, benchmark::internal::PerfCountersMeasurement*) const +0x168 [0x5585385d6498] #7 in ./cpp/build/ANN_BENCH(+0x149108) [0x5585385b7108] #8 in ./cpp/build/ANN_BENCH: benchmark::internal::BenchmarkRunner::DoNIterations() +0x34f [0x5585385b8c7f] #9 in ./cpp/build/ANN_BENCH: benchmark::internal::BenchmarkRunner::DoOneRepetition() +0x119 [0x5585385b99b9] #10 in ./cpp/build/ANN_BENCH(+0x13afdd) [0x5585385a8fdd] #11 in ./cpp/build/ANN_BENCH: benchmark::RunSpecifiedBenchmarks(benchmark::BenchmarkReporter*, benchmark::BenchmarkReporter*, std::__cxx11::basic_string, std::allocator >) +0x58e [0x5585385aa8fe] #12 in ./cpp/build/ANN_BENCH: benchmark::RunSpecifiedBenchmarks() +0x6a [0x5585385aaada] #13 in ./cpp/build/ANN_BENCH: raft::bench::ann::run_main(int, char**) +0x11ed [0x5585385980cd] #14 in /lib/x86_64-linux-gnu/libc.so.6(+0x28150) [0x7fb213e28150] #15 in /lib/x86_64-linux-gnu/libc.so.6: __libc_start_main +0x89 [0x7fb213e28209] #16 in ./cpp/build/ANN_BENCH(+0xbfcef) [0x55853852dcef] ``` Authors: - Artem M. Chirkin (https://github.com/achirkin) Approvers: - Tamas Bela Feher (https://github.com/tfeher) URL: https://github.com/rapidsai/raft/pull/2188 --- cpp/include/raft/core/error.hpp | 68 ++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/cpp/include/raft/core/error.hpp b/cpp/include/raft/core/error.hpp index 9045c5c871..6533e9c3c6 100644 --- a/cpp/include/raft/core/error.hpp +++ b/cpp/include/raft/core/error.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2023, NVIDIA CORPORATION. + * Copyright (c) 2019-2024, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,15 +19,23 @@ #pragma once +#if defined(__GNUC__) && __has_include() && __has_include() +#define ENABLE_COLLECT_CALLSTACK +#endif + #include -#include #include #include -#include #include #include #include +#ifdef ENABLE_COLLECT_CALLSTACK +#include +#include +#include +#endif + namespace raft { /** @@ -64,25 +72,67 @@ class exception : public std::exception { // Courtesy: https://www.gnu.org/software/libc/manual/html_node/Backtraces.html void collect_call_stack() noexcept { -#ifdef __GNUC__ +#ifdef ENABLE_COLLECT_CALLSTACK + constexpr int kSkipFrames = 1; constexpr int kMaxStackDepth = 64; void* stack[kMaxStackDepth]; // NOLINT auto depth = backtrace(stack, kMaxStackDepth); std::ostringstream oss; - oss << std::endl << "Obtained " << depth << " stack frames" << std::endl; + oss << std::endl << "Obtained " << (depth - kSkipFrames) << " stack frames" << std::endl; char** strings = backtrace_symbols(stack, depth); if (strings == nullptr) { oss << "But no stack trace could be found!" << std::endl; msg_ += oss.str(); return; } - ///@todo: support for demangling of C++ symbol names - for (int i = 0; i < depth; ++i) { - oss << "#" << i << " in " << strings[i] << std::endl; + // Courtesy: https://panthema.net/2008/0901-stacktrace-demangled/ + for (int i = kSkipFrames; i < depth; i++) { + oss << "#" << i << " in "; // beginning of the backtrace line + + char* mangled_name = nullptr; + char* offset_begin = nullptr; + char* offset_end = nullptr; + auto backtrace_line = strings[i]; + + // Find parentheses and +address offset surrounding mangled name + // e.g. ./module(function+0x15c) [0x8048a6d] + for (char* p = backtrace_line; *p != 0; p++) { + if (*p == '(') { + mangled_name = p; + } else if (*p == '+') { + offset_begin = p; + } else if (*p == ')') { + offset_end = p; + break; + } + } + + // Attempt to demangle the symbol + if (mangled_name != nullptr && offset_begin != nullptr && offset_end != nullptr && + mangled_name + 1 < offset_begin) { + // Split the backtrace_line + *mangled_name++ = 0; + *offset_begin++ = 0; + *offset_end++ = 0; + + // Demangle the name part + int status = 0; + char* real_name = abi::__cxa_demangle(mangled_name, nullptr, nullptr, &status); + + if (status == 0) { // Success: substitute the real name + oss << backtrace_line << ": " << real_name << " +" << offset_begin << offset_end; + } else { // Couldn't demangle + oss << backtrace_line << ": " << mangled_name << " +" << offset_begin << offset_end; + } + free(real_name); + } else { // Couldn't match the symbol name + oss << backtrace_line; + } + oss << std::endl; } free(strings); msg_ += oss.str(); -#endif // __GNUC__ +#endif } };