mirror of
https://github.com/zebrajr/pytorch.git
synced 2025-12-06 12:20:52 +01:00
Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/37101 Fixes #36954. The basic concept is to streamline the process of rethrowing c10::Error with extra error information. This is in a few steps: - I completely remodeled the Error data type and the internal invariants. Instead of manually adding in newlines, the message stack formatting process is responsible for inserting newlines and spacing as necessary. Call sites are then modified to respect the new API model. - TORCH_RETHROW macro is added, which adds context to an error message and then rethrows it. New internal assert failure looks like: ``` 0 INTERNAL ASSERT FAILED at ../c10/test/util/exception_test.cpp:64, please report a bug to PyTorch. Exception raised from TestBody at ../c10/test/util/exception_test.cpp:64 (most recent call first): frame #0: <unknown function> + 0x6aab9 (0x7ff611d3aab9 in /data/users/ezyang/pytorch-tmp/build/lib/libc10.so) frame #1: ... ``` Error message with context looks like: ``` This is an error This is context 1 This is context 2 ``` Signed-off-by: Edward Z. Yang <ezyang@fb.com> Test Plan: Imported from OSS Differential Revision: D21202891 Pulled By: ezyang fbshipit-source-id: 361cadd16bc52e5886dba08e79277771ada76169
142 lines
3.6 KiB
C++
142 lines
3.6 KiB
C++
#include <c10/util/Exception.h>
|
|
#include <c10/util/Backtrace.h>
|
|
#include <c10/util/Type.h>
|
|
#include <c10/util/Logging.h>
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <numeric>
|
|
#include <string>
|
|
|
|
namespace c10 {
|
|
|
|
Error::Error(std::string msg, std::string backtrace, const void* caller)
|
|
: msg_(std::move(msg)), backtrace_(std::move(backtrace)), caller_(caller) {
|
|
refresh_what();
|
|
}
|
|
|
|
// PyTorch-style error message
|
|
// Error::Error(SourceLocation source_location, const std::string& msg)
|
|
// NB: This is defined in Logging.cpp for access to GetFetchStackTrace
|
|
|
|
// Caffe2-style error message
|
|
Error::Error(
|
|
const char* file,
|
|
const uint32_t line,
|
|
const char* condition,
|
|
const std::string& msg,
|
|
const std::string& backtrace,
|
|
const void* caller)
|
|
: Error(
|
|
str("[enforce fail at ",
|
|
detail::StripBasename(file),
|
|
":",
|
|
line,
|
|
"] ",
|
|
condition,
|
|
". ",
|
|
msg),
|
|
backtrace,
|
|
caller) {}
|
|
|
|
std::string Error::compute_what(bool include_backtrace) const {
|
|
std::ostringstream oss;
|
|
|
|
oss << msg_;
|
|
|
|
if (context_.size() == 1) {
|
|
// Fold error and context in one line
|
|
oss << " (" << context_[0] << ")";
|
|
} else {
|
|
for (const auto& c : context_) {
|
|
oss << "\n " << c;
|
|
}
|
|
}
|
|
|
|
if (include_backtrace) {
|
|
oss << "\n" << backtrace_;
|
|
}
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
void Error::refresh_what() {
|
|
what_ = compute_what(/*include_backtrace*/ true);
|
|
what_without_backtrace_ = compute_what(/*include_backtrace*/ false);
|
|
}
|
|
|
|
void Error::add_context(std::string new_msg) {
|
|
context_.push_back(std::move(new_msg));
|
|
// TODO: Calling add_context O(n) times has O(n^2) cost. We can fix
|
|
// this perf problem by populating the fields lazily... if this ever
|
|
// actually is a problem.
|
|
// NB: If you do fix this, make sure you do it in a thread safe way!
|
|
// what() is almost certainly expected to be thread safe even when
|
|
// accessed across multiple threads
|
|
refresh_what();
|
|
}
|
|
|
|
namespace Warning {
|
|
|
|
namespace {
|
|
WarningHandler* getBaseHandler() {
|
|
static WarningHandler base_warning_handler_ = WarningHandler();
|
|
return &base_warning_handler_;
|
|
};
|
|
|
|
class ThreadWarningHandler {
|
|
public:
|
|
ThreadWarningHandler() = delete;
|
|
|
|
static WarningHandler* get_handler() {
|
|
if (!warning_handler_) {
|
|
warning_handler_ = getBaseHandler();
|
|
}
|
|
return warning_handler_;
|
|
}
|
|
|
|
static void set_handler(WarningHandler* handler) {
|
|
warning_handler_ = handler;
|
|
}
|
|
|
|
private:
|
|
static thread_local WarningHandler* warning_handler_;
|
|
};
|
|
|
|
thread_local WarningHandler* ThreadWarningHandler::warning_handler_ = nullptr;
|
|
|
|
}
|
|
|
|
void warn(SourceLocation source_location, const std::string& msg, const bool verbatim) {
|
|
ThreadWarningHandler::get_handler()->process(source_location, msg, verbatim);
|
|
}
|
|
|
|
void set_warning_handler(WarningHandler* handler) noexcept(true) {
|
|
ThreadWarningHandler::set_handler(handler);
|
|
}
|
|
|
|
WarningHandler* get_warning_handler() noexcept(true) {
|
|
return ThreadWarningHandler::get_handler();
|
|
}
|
|
|
|
} // namespace Warning
|
|
|
|
void WarningHandler::process(
|
|
const SourceLocation& source_location,
|
|
const std::string& msg,
|
|
const bool /*verbatim*/) {
|
|
LOG_AT_FILE_LINE(WARNING, source_location.file, source_location.line)
|
|
<< "Warning: " << msg << " (function " << source_location.function << ")";
|
|
}
|
|
|
|
|
|
std::string GetExceptionString(const std::exception& e) {
|
|
#ifdef __GXX_RTTI
|
|
return demangle(typeid(e).name()) + ": " + e.what();
|
|
#else
|
|
return std::string("Exception (no RTTI available): ") + e.what();
|
|
#endif // __GXX_RTTI
|
|
}
|
|
|
|
} // namespace c10
|