blob: 3f2c34ffae6c15db8aa5e0e4bc6605e62a28168a [file] [log] [blame]
#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