Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 74 additions & 29 deletions include/tvm/runtime/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,37 @@
#include <ctime>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>

/*!
* \brief Macro helper for exception throwing.
* \brief Macro helper to force a function not to be inlined.
* It is only used in places that we know not inlining is good,
* e.g. some logging functions.
*/
#if defined(_MSC_VER)
#define TVM_NO_INLINE __declspec(noinline)
#else
#define TVM_NO_INLINE __attribute__((noinline))
#endif

/*!
* \brief Macro helper to force a function to be inlined.
* It is only used in places that we know inline is important,
* e.g. some template expansion cases.
*/
#ifdef _MSC_VER
#define TVM_THROW_EXCEPTION noexcept(false) __declspec(noreturn)
#define TVM_ALWAYS_INLINE __forceinline
#else
#define TVM_THROW_EXCEPTION noexcept(false)
#define TVM_ALWAYS_INLINE inline __attribute__((always_inline))
#endif

/*!
* \brief Macro helper for exception throwing.
*/
#define TVM_THROW_EXCEPTION noexcept(false)

/*!
* \brief Whether or not enable backtrace logging during a
* fatal error.
Expand Down Expand Up @@ -181,7 +200,7 @@ class Error : public ::dmlc::Error { // for backwards compatibility

/*!
* \brief Error type for errors from CHECK, ICHECK, and LOG(FATAL). This error
* contains a backtrace of where it occured.
* contains a backtrace of where it occurred.
*/
class InternalError : public Error {
public:
Expand Down Expand Up @@ -291,24 +310,36 @@ class LogMessage {
/*!
* \brief Class to accumulate an error message and throw it. Do not use
* directly, instead use LOG(FATAL).
* \note The `LogFatal` class is designed to be an empty class to reduce stack size usage.
* To play this trick, we use the thread-local storage to store its internal data.
*/
class LogFatal {
public:
LogFatal(const std::string& file, int lineno) : file_(file), lineno_(lineno) {}
TVM_NO_INLINE LogFatal(const char* file, int lineno) { GetEntry().Init(file, lineno); }
#ifdef _MSC_VER
#pragma disagnostic push
#pragma warning(disable : 4722)
#endif
~LogFatal() noexcept(false) { throw InternalError(file_, lineno_, stream_.str()); }
~LogFatal() TVM_THROW_EXCEPTION { GetEntry().Finalize(); }
#ifdef _MSC_VER
#pragma disagnostic pop
#endif
std::ostringstream& stream() { return stream_; }
std::ostringstream& stream() { return GetEntry().stream_; }

private:
std::ostringstream stream_;
std::string file_;
int lineno_;
struct Entry {
void Init(const char* file, int lineno) {
this->stream_.str("");
this->file_ = file;
this->lineno_ = lineno;
}
TVM_NO_INLINE dmlc::Error Finalize() { throw InternalError(file_, lineno_, stream_.str()); }
std::ostringstream stream_;
std::string file_;
int lineno_;
};

TVM_DLL TVM_NO_INLINE static Entry& GetEntry();
};

/*!
Expand All @@ -322,7 +353,7 @@ class LogMessage {
stream_ << "[" << std::put_time(std::localtime(&t), "%H:%M:%S") << "] " << file << ":" << lineno
<< ": ";
}
~LogMessage() { std::cerr << stream_.str() << std::endl; }
TVM_NO_INLINE ~LogMessage() { std::cerr << stream_.str() << std::endl; }
std::ostringstream& stream() { return stream_; }

private:
Expand Down Expand Up @@ -361,19 +392,33 @@ inline bool DebugLoggingEnabled() {
}

constexpr const char* kTVM_INTERNAL_ERROR_MESSAGE =
"\n"
"---------------------------------------------------------------\n"
"An internal invariant was violated during the execution of TVM.\n"
"Please read TVM's error reporting guidelines.\n"
"More details can be found here: https://discuss.tvm.ai/t/error-reporting/7793.\n"
"---------------------------------------------------------------\n";

// Inline _Pragma in macros does not work reliably on old version of MVSC and
template <typename X, typename Y>
std::unique_ptr<std::string> LogCheckFormat(const X& x, const Y& y) {
std::ostringstream os;
os << " (" << x << " vs. " << y << ") "; // CHECK_XX(x, y) requires x and y can be serialized to
// string. Use CHECK(x OP y) otherwise.
// no std::make_unique until c++14
return std::unique_ptr<std::string>(new std::string(os.str()));
}

// Inline _Pragma in macros does not work reliably on old version of MSVC and
// GCC. We wrap all comparisons in a function so that we can use #pragma to
// silence bad comparison warnings.
#define TVM_CHECK_FUNC(name, op) \
template <typename A, typename B> \
DMLC_ALWAYS_INLINE bool LogCheck##name(const A& a, const B& b) { \
return a op b; \
#define TVM_CHECK_FUNC(name, op) \
template <typename X, typename Y> \
TVM_ALWAYS_INLINE std::unique_ptr<std::string> LogCheck##name(const X& x, const Y& y) { \
if (x op y) return nullptr; \
return LogCheckFormat(x, y); \
} \
TVM_ALWAYS_INLINE std::unique_ptr<std::string> LogCheck##name(int x, int y) { \
return LogCheck##name<int, int>(x, y); \
}

#pragma GCC diagnostic push
Expand All @@ -390,18 +435,18 @@ TVM_CHECK_FUNC(_NE, !=)
#define LOG(level) LOG_##level
#define LOG_FATAL ::tvm::runtime::detail::LogFatal(__FILE__, __LINE__).stream()
#define LOG_INFO ::tvm::runtime::detail::LogMessage(__FILE__, __LINE__).stream()
#define LOG_ERROR (::tvm::runtime::detail::LogMessage(__FILE__, __LINE__).stream() << "error: ")
#define LOG_WARNING (::tvm::runtime::detail::LogMessage(__FILE__, __LINE__).stream() << "warning: ")
#define LOG_ERROR (::tvm::runtime::detail::LogMessage(__FILE__, __LINE__).stream() << "Error: ")
#define LOG_WARNING (::tvm::runtime::detail::LogMessage(__FILE__, __LINE__).stream() << "Warning: ")

#define TVM_CHECK_BINARY_OP(name, op, x, y) \
if (!::tvm::runtime::detail::LogCheck##name(x, y)) \
::tvm::runtime::detail::LogFatal(__FILE__, __LINE__).stream() \
<< "Check failed: " << #x " " #op " " #y << ": "
#define TVM_CHECK_BINARY_OP(name, op, x, y) \
if (auto __tvm__log__err = ::tvm::runtime::detail::LogCheck##name(x, y)) \
::tvm::runtime::detail::LogFatal(__FILE__, __LINE__).stream() \
<< "Check failed: " << #x " " #op " " #y << *__tvm__log__err << ": "

#define CHECK(x) \
if (!(x)) \
::tvm::runtime::detail::LogFatal(__FILE__, __LINE__).stream() \
<< "Check failed: " #x << " == false: "
<< "Check failed: (" #x << ") is false: "

#define CHECK_LT(x, y) TVM_CHECK_BINARY_OP(_LT, <, x, y)
#define CHECK_GT(x, y) TVM_CHECK_BINARY_OP(_GT, >, x, y)
Expand Down Expand Up @@ -462,17 +507,17 @@ TVM_CHECK_FUNC(_NE, !=)

#define TVM_ICHECK_INDENT " "

#define ICHECK_BINARY_OP(name, op, x, y) \
if (!::tvm::runtime::detail::LogCheck##name(x, y)) \
::tvm::runtime::detail::LogFatal(__FILE__, __LINE__).stream() \
<< ::tvm::runtime::detail::kTVM_INTERNAL_ERROR_MESSAGE << std::endl \
<< TVM_ICHECK_INDENT << "Check failed: " << #x " " #op " " #y << ": "
#define ICHECK_BINARY_OP(name, op, x, y) \
if (auto __tvm__log__err = ::tvm::runtime::detail::LogCheck##name(x, y)) \
::tvm::runtime::detail::LogFatal(__FILE__, __LINE__).stream() \
<< ::tvm::runtime::detail::kTVM_INTERNAL_ERROR_MESSAGE << std::endl \
<< TVM_ICHECK_INDENT << "Check failed: " << #x " " #op " " #y << *__tvm__log__err << ": "

#define ICHECK(x) \
if (!(x)) \
::tvm::runtime::detail::LogFatal(__FILE__, __LINE__).stream() \
<< ::tvm::runtime::detail::kTVM_INTERNAL_ERROR_MESSAGE << TVM_ICHECK_INDENT \
<< "Check failed: " #x << " == false: "
<< "Check failed: (" #x << ") is false: "

#define ICHECK_LT(x, y) ICHECK_BINARY_OP(_LT, <, x, y)
#define ICHECK_GT(x, y) ICHECK_BINARY_OP(_GT, >, x, y)
Expand Down
12 changes: 2 additions & 10 deletions include/tvm/runtime/packed_func.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,6 @@
#define TVM_RUNTIME_HEADER_ONLY 0
#endif

// Always inline macro only use in template
// expansion cases where we know inline is important.
#ifdef _MSC_VER
#define TVM_ALWAYS_INLINE __forceinline
#else
#define TVM_ALWAYS_INLINE inline __attribute__((always_inline))
#endif

namespace tvm {
namespace runtime {

Expand Down Expand Up @@ -743,7 +735,7 @@ class TVMRetValue : public TVMPODValue_ {
/*! \brief default constructor */
TVMRetValue() {}
/*!
* \brief move constructor from anoter return value.
* \brief move constructor from another return value.
* \param other The other return value.
*/
TVMRetValue(TVMRetValue&& other) : TVMPODValue_(other.value_, other.type_code_) {
Expand Down Expand Up @@ -1119,7 +1111,7 @@ struct PackedFuncValueConverter {
* });
*
* // The following code will cause compilation error.
* // Because the same Function and ExortName
* // Because the same Function and ExportName
* // TVM_DLL_EXPORT_TYPED_FUNC(AddOne_, AddOne_);
*
* // The following code is OK, assuming the macro
Expand Down
14 changes: 14 additions & 0 deletions src/runtime/logging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,17 @@ std::string Backtrace() { return ""; }
} // namespace runtime
} // namespace tvm
#endif // TVM_LOG_STACK_TRACE

#if (TVM_LOG_CUSTOMIZE == 0)
namespace tvm {
namespace runtime {
namespace detail {

LogFatal::Entry& LogFatal::GetEntry() {
static thread_local LogFatal::Entry result;
return result;
}
} // namespace detail
} // namespace runtime
} // namespace tvm
#endif // TVM_LOG_CUSTOMIZE