Skip to content

Commit

Permalink
Demangle backtrace symbols on raft error (#2188)
Browse files Browse the repository at this point in the history
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<char, std::char_traits<char>, std::allocator<char> > 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<float, long>::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<float>(benchmark::State&, raft::bench::ann::Configuration::Index, unsigned long, std::shared_ptr<raft::bench::ann::Dataset<float> const>, raft::bench::ann::Objective) +0xf76 [0x55853859f586]
#5 in ./cpp/build/ANN_BENCH: benchmark::internal::LambdaBenchmark<benchmark::RegisterBenchmark<void (&)(benchmark::State&, raft::bench::ann::Configuration::Index, unsigned long, std::shared_ptr<raft::bench::ann::Dataset<float> const>, raft::bench::ann::Objective), raft::bench::ann::Configuration::Index&, unsigned long&, std::shared_ptr<raft::bench::ann::Dataset<float> const>&, raft::bench::ann::Objective&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, void (&)(benchmark::State&, raft::bench::ann::Configuration::Index, unsigned long, std::shared_ptr<raft::bench::ann::Dataset<float> const>, raft::bench::ann::Objective), raft::bench::ann::Configuration::Index&, unsigned long&, std::shared_ptr<raft::bench::ann::Dataset<float> 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<char, std::char_traits<char>, std::allocator<char> >) +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: #2188
  • Loading branch information
achirkin authored Feb 15, 2024
1 parent addb485 commit 4f56238
Showing 1 changed file with 59 additions and 9 deletions.
68 changes: 59 additions & 9 deletions cpp/include/raft/core/error.hpp
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -19,15 +19,23 @@

#pragma once

#if defined(__GNUC__) && __has_include(<cxxabi.h>) && __has_include(<execinfo.h>)
#define ENABLE_COLLECT_CALLSTACK
#endif

#include <cstdio>
#include <execinfo.h>
#include <iostream>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>

#ifdef ENABLE_COLLECT_CALLSTACK
#include <cxxabi.h>
#include <execinfo.h>
#include <sstream>
#endif

namespace raft {

/**
Expand Down Expand Up @@ -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
}
};

Expand Down

0 comments on commit 4f56238

Please sign in to comment.