mirror of
https://github.com/zebrajr/pytorch.git
synced 2025-12-07 12:21:27 +01:00
[caffe2] Make all get_backtrace() implementations lazy (#125750)
Summary: #125682 (D56586844) added support for lazy symbolization to `Error` and adopted it for internal use cases; this commit adopts it for `get_backtrace()` as well. Test Plan: Sandcastle and GH CI. Differential Revision: D56881683 Pull Request resolved: https://github.com/pytorch/pytorch/pull/125750 Approved by: https://github.com/ezyang
This commit is contained in:
parent
31372fa842
commit
cc4da72b47
|
|
@ -31,7 +31,30 @@
|
|||
|
||||
namespace c10 {
|
||||
|
||||
#if SUPPORTS_BACKTRACE && defined(C10_ANDROID)
|
||||
namespace {
|
||||
|
||||
#ifdef FBCODE_CAFFE2
|
||||
|
||||
// For some reason, the stacktrace implementation in fbcode is better than ours,
|
||||
// see https://github.com/pytorch/pytorch/issues/56399 When it's available, just
|
||||
// use that.
|
||||
class GetBacktraceImpl {
|
||||
public:
|
||||
C10_ALWAYS_INLINE GetBacktraceImpl(
|
||||
size_t frames_to_skip,
|
||||
size_t /* maximum_number_of_frames */,
|
||||
bool /* skip_python_frames */)
|
||||
: st_(/*skipFrames=*/frames_to_skip) {}
|
||||
|
||||
std::string symbolize() const {
|
||||
return st_.toString();
|
||||
}
|
||||
|
||||
private:
|
||||
facebook::process::StackTrace st_;
|
||||
};
|
||||
|
||||
#elif SUPPORTS_BACKTRACE && defined(C10_ANDROID)
|
||||
|
||||
struct AndroidBacktraceState {
|
||||
std::vector<void*> buffer;
|
||||
|
|
@ -48,44 +71,49 @@ _Unwind_Reason_Code android_unwind_callback(
|
|||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
void dump_stack(
|
||||
std::ostream& os,
|
||||
size_t frames_to_skip,
|
||||
size_t maximum_number_of_frames) {
|
||||
AndroidBacktraceState state;
|
||||
class GetBacktraceImpl {
|
||||
public:
|
||||
C10_ALWAYS_INLINE GetBacktraceImpl(
|
||||
size_t /* frames_to_skip */,
|
||||
size_t /* maximum_number_of_frames */,
|
||||
bool /* skip_python_frames */)
|
||||
: st_(/* skipFrames */ frames_to_skip);
|
||||
{ _Unwind_Backtrace(android_unwind_callback, &state_); }
|
||||
|
||||
_Unwind_Backtrace(android_unwind_callback, &state);
|
||||
std::string symbolize() const {
|
||||
std::ostringstream os;
|
||||
int idx = 0;
|
||||
char* demangled = nullptr;
|
||||
size_t length = 0;
|
||||
|
||||
int idx = 0;
|
||||
char* demangled = nullptr;
|
||||
size_t length = 0;
|
||||
for (const void* addr : state_.buffer) {
|
||||
const char* symbol = "";
|
||||
|
||||
for (const void* addr : state.buffer) {
|
||||
const char* symbol = "";
|
||||
Dl_info info;
|
||||
if (dladdr(addr, &info) && info.dli_sname) {
|
||||
symbol = info.dli_sname;
|
||||
}
|
||||
|
||||
Dl_info info;
|
||||
if (dladdr(addr, &info) && info.dli_sname) {
|
||||
symbol = info.dli_sname;
|
||||
int status = 0;
|
||||
demangled = __cxxabiv1::__cxa_demangle(
|
||||
/*mangled_name*/ symbol,
|
||||
/*output_buffer*/ demangled,
|
||||
/*length*/ &length,
|
||||
/*status*/ &status);
|
||||
|
||||
os << " frame #" << idx++ << "\t"
|
||||
<< ((demangled != NULL && status == 0) ? demangled : symbol) << "["
|
||||
<< addr << "]\t" << std::endl;
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
demangled = __cxxabiv1::__cxa_demangle(
|
||||
/*mangled_name*/ symbol,
|
||||
/*output_buffer*/ demangled,
|
||||
/*length*/ &length,
|
||||
/*status*/ &status);
|
||||
|
||||
os << " frame #" << idx++ << "\t"
|
||||
<< ((demangled != NULL && status == 0) ? demangled : symbol) << "["
|
||||
<< addr << "]\t" << std::endl;
|
||||
free(demangled);
|
||||
return os.str();
|
||||
}
|
||||
free(demangled);
|
||||
}
|
||||
|
||||
#endif /* SUPPORTS_BACKTRACE && defined(C10_ANDROID) */
|
||||
private:
|
||||
AndroidBacktraceState state_;
|
||||
};
|
||||
|
||||
#if SUPPORTS_BACKTRACE
|
||||
namespace {
|
||||
#elif SUPPORTS_BACKTRACE // !defined(C10_ANDROID)
|
||||
|
||||
struct FrameInformation {
|
||||
/// If available, the demangled name of the function at this frame, else
|
||||
|
|
@ -101,7 +129,6 @@ struct FrameInformation {
|
|||
std::string object_file;
|
||||
};
|
||||
|
||||
#ifndef C10_ANDROID
|
||||
bool is_python_frame(const FrameInformation& frame) {
|
||||
return frame.object_file == "python" || frame.object_file == "python3" ||
|
||||
(frame.object_file.find("libpython") != std::string::npos);
|
||||
|
|
@ -173,10 +200,89 @@ c10::optional<FrameInformation> parse_frame_information(
|
|||
frame.function_name = demangle(mangled_function_name.c_str());
|
||||
return frame;
|
||||
}
|
||||
#endif /* !defined(C10_ANDROID) */
|
||||
} // anonymous namespace
|
||||
#elif defined(_MSC_VER)
|
||||
namespace {
|
||||
|
||||
class GetBacktraceImpl {
|
||||
public:
|
||||
C10_ALWAYS_INLINE GetBacktraceImpl(
|
||||
size_t frames_to_skip,
|
||||
size_t maximum_number_of_frames,
|
||||
bool skip_python_frames)
|
||||
: skip_python_frames_(skip_python_frames),
|
||||
callstack_(frames_to_skip + maximum_number_of_frames, nullptr) {
|
||||
// We always skip this frame (backtrace).
|
||||
frames_to_skip += 1;
|
||||
|
||||
// backtrace() gives us a list of return addresses in the current call
|
||||
// stack. NOTE: As per man (3) backtrace it can never fail
|
||||
// (http://man7.org/linux/man-pages/man3/backtrace.3.html).
|
||||
auto number_of_frames = static_cast<size_t>(
|
||||
::backtrace(callstack_.data(), static_cast<int>(callstack_.size())));
|
||||
|
||||
// Skip as many frames as requested.
|
||||
frames_to_skip = std::min(frames_to_skip, number_of_frames);
|
||||
number_of_frames -= frames_to_skip;
|
||||
callstack_.erase(
|
||||
callstack_.begin(),
|
||||
callstack_.begin() + static_cast<ssize_t>(frames_to_skip));
|
||||
callstack_.resize(number_of_frames);
|
||||
}
|
||||
|
||||
std::string symbolize() const {
|
||||
// `backtrace_symbols` takes the return addresses obtained from
|
||||
// `backtrace()` and fetches string representations of each stack.
|
||||
// Unfortunately it doesn't return a struct of individual pieces of
|
||||
// information but a concatenated string, so we'll have to parse the string
|
||||
// after. NOTE: The array returned by `backtrace_symbols` is malloc'd and
|
||||
// must be manually freed, but not the strings inside the array.
|
||||
std::unique_ptr<char*, std::function<void(char**)>> raw_symbols(
|
||||
::backtrace_symbols(
|
||||
callstack_.data(), static_cast<int>(callstack_.size())),
|
||||
/*deleter=*/free);
|
||||
const std::vector<std::string> symbols(
|
||||
raw_symbols.get(), raw_symbols.get() + callstack_.size());
|
||||
|
||||
// The backtrace string goes into here.
|
||||
std::ostringstream stream;
|
||||
|
||||
// Toggles to true after the first skipped python frame.
|
||||
bool has_skipped_python_frames = false;
|
||||
|
||||
for (const auto frame_number : c10::irange(callstack_.size())) {
|
||||
const auto frame = parse_frame_information(symbols[frame_number]);
|
||||
|
||||
if (skip_python_frames_ && frame && is_python_frame(*frame)) {
|
||||
if (!has_skipped_python_frames) {
|
||||
stream << "<omitting python frames>\n";
|
||||
has_skipped_python_frames = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// frame #<number>:
|
||||
stream << "frame #" << frame_number << ": ";
|
||||
|
||||
if (frame) {
|
||||
// <function_name> + <offset> (<return-address> in <object-file>)
|
||||
stream << frame->function_name << " + " << frame->offset_into_function
|
||||
<< " (" << callstack_[frame_number] << " in "
|
||||
<< frame->object_file << ")\n";
|
||||
} else {
|
||||
// In the edge-case where we couldn't parse the frame string, we can
|
||||
// just use it directly (it may have a different format).
|
||||
stream << symbols[frame_number] << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
private:
|
||||
const bool skip_python_frames_;
|
||||
std::vector<void*> callstack_;
|
||||
};
|
||||
|
||||
#elif defined(_MSC_VER) // !SUPPORTS_BACKTRACE
|
||||
|
||||
const int max_name_len = 256;
|
||||
std::string get_module_base_name(void* addr) {
|
||||
HMODULE h_module;
|
||||
|
|
@ -225,180 +331,144 @@ class SymbolHelper {
|
|||
SymbolHelper(SymbolHelper const&) = delete;
|
||||
void operator=(SymbolHelper const&) = delete;
|
||||
};
|
||||
} // anonymous namespace
|
||||
#endif // SUPPORTS_BACKTRACE
|
||||
|
||||
// This backtrace retrieval is implemented on Windows via the Windows API using
|
||||
// `CaptureStackBackTrace`, `SymFromAddr` and `SymGetLineFromAddr64`.
|
||||
// https://stackoverflow.com/questions/5693192/win32-backtrace-from-c-code
|
||||
// https://stackoverflow.com/questions/26398064/counterpart-to-glibcs-backtrace-and-backtrace-symbols-on-windows
|
||||
// https://docs.microsoft.com/en-us/windows/win32/debug/capturestackbacktrace
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symfromaddr
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symgetlinefromaddr64
|
||||
// TODO: Support skipping python frames
|
||||
class GetBacktraceImpl {
|
||||
public:
|
||||
C10_ALWAYS_INLINE GetBacktraceImpl(
|
||||
size_t frames_to_skip,
|
||||
size_t maximum_number_of_frames,
|
||||
bool /* skip_python_frames */)
|
||||
: back_trace_(new void*[maximum_number_of_frames]) {
|
||||
// We always skip this frame (backtrace).
|
||||
frames_to_skip += 1;
|
||||
|
||||
// Get the frames
|
||||
n_frame_ = CaptureStackBackTrace(
|
||||
static_cast<DWORD>(frames_to_skip),
|
||||
static_cast<DWORD>(maximum_number_of_frames),
|
||||
back_trace_.get(),
|
||||
NULL);
|
||||
}
|
||||
|
||||
std::string symbolize() const {
|
||||
DWORD64 displacement;
|
||||
DWORD disp;
|
||||
std::unique_ptr<IMAGEHLP_LINE64> line;
|
||||
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
|
||||
PSYMBOL_INFO p_symbol = (PSYMBOL_INFO)buffer;
|
||||
|
||||
bool with_symbol = false;
|
||||
bool with_line = false;
|
||||
|
||||
// The backtrace string goes into here.
|
||||
std::ostringstream stream;
|
||||
|
||||
// Initialize symbols if necessary
|
||||
SymbolHelper& sh = SymbolHelper::getInstance();
|
||||
|
||||
for (USHORT i_frame = 0; i_frame < n_frame_; ++i_frame) {
|
||||
// Get the address and the name of the symbol
|
||||
if (sh.inited) {
|
||||
p_symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
p_symbol->MaxNameLen = MAX_SYM_NAME;
|
||||
with_symbol = SymFromAddr(
|
||||
sh.process, (ULONG64)back_trace_[i_frame], &displacement, p_symbol);
|
||||
}
|
||||
|
||||
// Get the line number and the module
|
||||
if (sh.inited) {
|
||||
line.reset(new IMAGEHLP_LINE64());
|
||||
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
with_line = SymGetLineFromAddr64(
|
||||
sh.process, (ULONG64)back_trace_[i_frame], &disp, line.get());
|
||||
}
|
||||
|
||||
// Get the module basename
|
||||
std::string module = get_module_base_name(back_trace_[i_frame]);
|
||||
|
||||
// The pattern on Windows is
|
||||
// `<return-address> <symbol-address>
|
||||
// <module-name>!<demangled-function-name> [<file-name> @ <line-number>]
|
||||
stream << std::setfill('0') << std::setw(16) << std::uppercase << std::hex
|
||||
<< back_trace_[i_frame] << std::dec;
|
||||
if (with_symbol) {
|
||||
stream << std::setfill('0') << std::setw(16) << std::uppercase
|
||||
<< std::hex << p_symbol->Address << std::dec << " " << module
|
||||
<< "!" << p_symbol->Name;
|
||||
} else {
|
||||
stream << " <unknown symbol address> " << module << "!<unknown symbol>";
|
||||
}
|
||||
stream << " [";
|
||||
if (with_line) {
|
||||
stream << line->FileName << " @ " << line->LineNumber;
|
||||
} else {
|
||||
stream << "<unknown file> @ <unknown line number>";
|
||||
}
|
||||
stream << "]" << std::endl;
|
||||
}
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<void*[]> back_trace_;
|
||||
USHORT n_frame_;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class GetBacktraceImpl {
|
||||
public:
|
||||
C10_ALWAYS_INLINE GetBacktraceImpl(
|
||||
size_t /* frames_to_skip */,
|
||||
size_t /* maximum_number_of_frames */,
|
||||
bool /* skip_python_frames */) {}
|
||||
|
||||
std::string symbolize() const {
|
||||
return "(no backtrace available)";
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string get_backtrace(
|
||||
size_t frames_to_skip,
|
||||
size_t maximum_number_of_frames,
|
||||
bool skip_python_frames) {
|
||||
#ifdef FBCODE_CAFFE2
|
||||
// For some reason, the stacktrace implementation in fbcode is
|
||||
// better than ours, see https://github.com/pytorch/pytorch/issues/56399
|
||||
// When it's available, just use that.
|
||||
facebook::process::StackTrace st;
|
||||
return st.toString();
|
||||
return GetBacktraceImpl{
|
||||
frames_to_skip, maximum_number_of_frames, skip_python_frames}
|
||||
.symbolize();
|
||||
}
|
||||
|
||||
#elif SUPPORTS_BACKTRACE && !defined(C10_ANDROID)
|
||||
Backtrace get_lazy_backtrace(
|
||||
size_t frames_to_skip,
|
||||
size_t maximum_number_of_frames,
|
||||
bool skip_python_frames) {
|
||||
class LazyBacktrace : public OptimisticLazyValue<std::string> {
|
||||
public:
|
||||
LazyBacktrace(GetBacktraceImpl&& impl) : impl_(std::move(impl)) {}
|
||||
|
||||
// We always skip this frame (backtrace).
|
||||
frames_to_skip += 1;
|
||||
|
||||
std::vector<void*> callstack(
|
||||
frames_to_skip + maximum_number_of_frames, nullptr);
|
||||
// backtrace() gives us a list of return addresses in the current call stack.
|
||||
// NOTE: As per man (3) backtrace it can never fail
|
||||
// (http://man7.org/linux/man-pages/man3/backtrace.3.html).
|
||||
auto number_of_frames =
|
||||
::backtrace(callstack.data(), static_cast<int>(callstack.size()));
|
||||
|
||||
// Skip as many frames as requested. This is not efficient, but the sizes here
|
||||
// are small and it makes the code nicer and safer.
|
||||
for (; frames_to_skip > 0 && number_of_frames > 0;
|
||||
--frames_to_skip, --number_of_frames) {
|
||||
callstack.erase(callstack.begin());
|
||||
}
|
||||
|
||||
// `number_of_frames` is strictly less than the current capacity of
|
||||
// `callstack`, so this is just a pointer subtraction and makes the subsequent
|
||||
// code safer.
|
||||
callstack.resize(static_cast<size_t>(number_of_frames));
|
||||
|
||||
// `backtrace_symbols` takes the return addresses obtained from `backtrace()`
|
||||
// and fetches string representations of each stack. Unfortunately it doesn't
|
||||
// return a struct of individual pieces of information but a concatenated
|
||||
// string, so we'll have to parse the string after. NOTE: The array returned
|
||||
// by `backtrace_symbols` is malloc'd and must be manually freed, but not the
|
||||
// strings inside the array.
|
||||
std::unique_ptr<char*, std::function<void(char**)>> raw_symbols(
|
||||
::backtrace_symbols(callstack.data(), static_cast<int>(callstack.size())),
|
||||
/*deleter=*/free);
|
||||
const std::vector<std::string> symbols(
|
||||
raw_symbols.get(), raw_symbols.get() + callstack.size());
|
||||
|
||||
// The backtrace string goes into here.
|
||||
std::ostringstream stream;
|
||||
|
||||
// Toggles to true after the first skipped python frame.
|
||||
bool has_skipped_python_frames = false;
|
||||
|
||||
for (const auto frame_number : c10::irange(callstack.size())) {
|
||||
const auto frame = parse_frame_information(symbols[frame_number]);
|
||||
|
||||
if (skip_python_frames && frame && is_python_frame(*frame)) {
|
||||
if (!has_skipped_python_frames) {
|
||||
stream << "<omitting python frames>\n";
|
||||
has_skipped_python_frames = true;
|
||||
}
|
||||
continue;
|
||||
private:
|
||||
std::string compute() const override {
|
||||
return impl_.symbolize();
|
||||
}
|
||||
|
||||
// frame #<number>:
|
||||
stream << "frame #" << frame_number << ": ";
|
||||
GetBacktraceImpl impl_;
|
||||
};
|
||||
|
||||
if (frame) {
|
||||
// <function_name> + <offset> (<return-address> in <object-file>)
|
||||
stream << frame->function_name << " + " << frame->offset_into_function
|
||||
<< " (" << callstack[frame_number] << " in " << frame->object_file
|
||||
<< ")\n";
|
||||
} else {
|
||||
// In the edge-case where we couldn't parse the frame string, we can
|
||||
// just use it directly (it may have a different format).
|
||||
stream << symbols[frame_number] << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return stream.str();
|
||||
|
||||
#elif SUPPORTS_BACKTRACE && defined(C10_ANDROID)
|
||||
|
||||
std::ostringstream oss;
|
||||
dump_stack(oss, frames_to_skip, maximum_number_of_frames);
|
||||
return oss.str().c_str();
|
||||
|
||||
#elif defined(_MSC_VER) // !SUPPORTS_BACKTRACE
|
||||
// This backtrace retrieval is implemented on Windows via the Windows
|
||||
// API using `CaptureStackBackTrace`, `SymFromAddr` and
|
||||
// `SymGetLineFromAddr64`.
|
||||
// https://stackoverflow.com/questions/5693192/win32-backtrace-from-c-code
|
||||
// https://stackoverflow.com/questions/26398064/counterpart-to-glibcs-backtrace-and-backtrace-symbols-on-windows
|
||||
// https://docs.microsoft.com/en-us/windows/win32/debug/capturestackbacktrace
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symfromaddr
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symgetlinefromaddr64
|
||||
// TODO: Support skipping python frames
|
||||
|
||||
// We always skip this frame (backtrace).
|
||||
frames_to_skip += 1;
|
||||
|
||||
DWORD64 displacement;
|
||||
DWORD disp;
|
||||
std::unique_ptr<IMAGEHLP_LINE64> line;
|
||||
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
|
||||
PSYMBOL_INFO p_symbol = (PSYMBOL_INFO)buffer;
|
||||
|
||||
std::unique_ptr<void*[]> back_trace(new void*[maximum_number_of_frames]);
|
||||
bool with_symbol = false;
|
||||
bool with_line = false;
|
||||
|
||||
// The backtrace string goes into here.
|
||||
std::ostringstream stream;
|
||||
|
||||
// Get the frames
|
||||
const USHORT n_frame = CaptureStackBackTrace(
|
||||
static_cast<DWORD>(frames_to_skip),
|
||||
static_cast<DWORD>(maximum_number_of_frames),
|
||||
back_trace.get(),
|
||||
NULL);
|
||||
|
||||
// Initialize symbols if necessary
|
||||
SymbolHelper& sh = SymbolHelper::getInstance();
|
||||
|
||||
for (USHORT i_frame = 0; i_frame < n_frame; ++i_frame) {
|
||||
// Get the address and the name of the symbol
|
||||
if (sh.inited) {
|
||||
p_symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
p_symbol->MaxNameLen = MAX_SYM_NAME;
|
||||
with_symbol = SymFromAddr(
|
||||
sh.process, (ULONG64)back_trace[i_frame], &displacement, p_symbol);
|
||||
}
|
||||
|
||||
// Get the line number and the module
|
||||
if (sh.inited) {
|
||||
line.reset(new IMAGEHLP_LINE64());
|
||||
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
with_line = SymGetLineFromAddr64(
|
||||
sh.process, (ULONG64)back_trace[i_frame], &disp, line.get());
|
||||
}
|
||||
|
||||
// Get the module basename
|
||||
std::string module = get_module_base_name(back_trace[i_frame]);
|
||||
|
||||
// The pattern on Windows is
|
||||
// `<return-address> <symbol-address>
|
||||
// <module-name>!<demangled-function-name> [<file-name> @ <line-number>]
|
||||
stream << std::setfill('0') << std::setw(16) << std::uppercase << std::hex
|
||||
<< back_trace[i_frame] << std::dec;
|
||||
if (with_symbol) {
|
||||
stream << std::setfill('0') << std::setw(16) << std::uppercase << std::hex
|
||||
<< p_symbol->Address << std::dec << " " << module << "!"
|
||||
<< p_symbol->Name;
|
||||
} else {
|
||||
stream << " <unknown symbol address> " << module << "!<unknown symbol>";
|
||||
}
|
||||
stream << " [";
|
||||
if (with_line) {
|
||||
stream << line->FileName << " @ " << line->LineNumber;
|
||||
} else {
|
||||
stream << "<unknown file> @ <unknown line number>";
|
||||
}
|
||||
stream << "]" << std::endl;
|
||||
}
|
||||
|
||||
return stream.str();
|
||||
#else // !SUPPORTS_BACKTRACE && !_WIN32
|
||||
return "(no backtrace available)";
|
||||
#endif // SUPPORTS_BACKTRACE
|
||||
return std::make_shared<LazyBacktrace>(GetBacktraceImpl{
|
||||
frames_to_skip, maximum_number_of_frames, skip_python_frames});
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
|
|
|||
|
|
@ -2,16 +2,30 @@
|
|||
#define C10_UTIL_BACKTRACE_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Lazy.h>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// Symbolizing the backtrace can be expensive; pass it around as a lazy string
|
||||
// so it is symbolized only if actually needed.
|
||||
using Backtrace = std::shared_ptr<const LazyValue<std::string>>;
|
||||
|
||||
// DEPRECATED: Prefer get_lazy_backtrace().
|
||||
C10_API std::string get_backtrace(
|
||||
size_t frames_to_skip = 0,
|
||||
size_t maximum_number_of_frames = 64,
|
||||
bool skip_python_frames = true);
|
||||
|
||||
C10_API Backtrace get_lazy_backtrace(
|
||||
size_t frames_to_skip = 0,
|
||||
size_t maximum_number_of_frames = 64,
|
||||
bool skip_python_frames = true);
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#endif // C10_UTIL_BACKTRACE_H_
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ std::string Error::compute_what(bool include_backtrace) const {
|
|||
return oss.str();
|
||||
}
|
||||
|
||||
const Error::Backtrace& Error::backtrace() const {
|
||||
const Backtrace& Error::backtrace() const {
|
||||
return backtrace_;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <c10/macros/Export.h>
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Backtrace.h>
|
||||
#include <c10/util/Lazy.h>
|
||||
#include <c10/util/StringUtil.h>
|
||||
|
||||
|
|
@ -27,11 +28,6 @@ namespace c10 {
|
|||
/// NB: c10::Error is handled specially by the default torch to suppress the
|
||||
/// backtrace, see torch/csrc/Exceptions.h
|
||||
class C10_API Error : public std::exception {
|
||||
public:
|
||||
// Symbolizing the backtrace can be expensive; pass it around as a lazy string
|
||||
// so it is symbolized only if actually needed.
|
||||
using Backtrace = std::shared_ptr<const LazyValue<std::string>>;
|
||||
|
||||
private:
|
||||
// The actual error message.
|
||||
std::string msg_;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include <c10/util/Lazy.h>
|
||||
#include <c10/util/Logging.h>
|
||||
#ifdef FBCODE_CAFFE2
|
||||
#include <common/process/StackTrace.h>
|
||||
#include <folly/synchronization/SanitizeThread.h>
|
||||
#endif
|
||||
|
||||
|
|
@ -26,30 +25,15 @@ C10_DEFINE_bool(
|
|||
namespace c10 {
|
||||
|
||||
namespace {
|
||||
std::function<::c10::Error::Backtrace()>& GetFetchStackTrace() {
|
||||
static std::function<::c10::Error::Backtrace()> func = []() {
|
||||
#ifdef FBCODE_CAFFE2
|
||||
// Same implementation as get_backtrace() in fbcode, but with lazy
|
||||
// symbolization.
|
||||
class LazyBacktrace : public OptimisticLazyValue<std::string> {
|
||||
facebook::process::StackTrace st_;
|
||||
|
||||
std::string compute() const override {
|
||||
return st_.toString();
|
||||
}
|
||||
};
|
||||
|
||||
return std::make_shared<LazyBacktrace>();
|
||||
#else
|
||||
return std::make_shared<PrecomputedLazyValue<std::string>>(
|
||||
get_backtrace(/*frames_to_skip=*/1));
|
||||
#endif
|
||||
std::function<::c10::Backtrace()>& GetFetchStackTrace() {
|
||||
static std::function<::c10::Backtrace()> func = []() {
|
||||
return get_lazy_backtrace(/*frames_to_skip=*/1);
|
||||
};
|
||||
return func;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void SetStackTraceFetcher(std::function<::c10::Error::Backtrace()> fetcher) {
|
||||
void SetStackTraceFetcher(std::function<::c10::Backtrace()> fetcher) {
|
||||
GetFetchStackTrace() = std::move(fetcher);
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +100,7 @@ class PyTorchStyleBacktrace : public OptimisticLazyValue<std::string> {
|
|||
backtrace_->get());
|
||||
}
|
||||
|
||||
::c10::Error::Backtrace backtrace_;
|
||||
::c10::Backtrace backtrace_;
|
||||
SourceLocation source_location_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <sstream>
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Backtrace.h>
|
||||
#include <c10/util/Exception.h>
|
||||
#include <c10/util/Flags.h>
|
||||
#include <c10/util/StringUtil.h>
|
||||
|
|
@ -126,8 +127,7 @@ constexpr bool IsUsingGoogleLogging() {
|
|||
*/
|
||||
C10_API void ShowLogInfoToStderr();
|
||||
|
||||
C10_API void SetStackTraceFetcher(
|
||||
std::function<::c10::Error::Backtrace()> fetcher);
|
||||
C10_API void SetStackTraceFetcher(std::function<::c10::Backtrace()> fetcher);
|
||||
|
||||
/**
|
||||
* Convenience function for non-lazy stack trace fetchers. The Backtrace
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user