diff --git a/include/tvm/runtime/logging.h b/include/tvm/runtime/logging.h index 08c6ff61252b..8a69c2ad7749 100644 --- a/include/tvm/runtime/logging.h +++ b/include/tvm/runtime/logging.h @@ -35,18 +35,37 @@ #include #include #include +#include #include #include /*! - * \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. @@ -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: @@ -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(); }; /*! @@ -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: @@ -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 +std::unique_ptr 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(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 \ - DMLC_ALWAYS_INLINE bool LogCheck##name(const A& a, const B& b) { \ - return a op b; \ +#define TVM_CHECK_FUNC(name, op) \ + template \ + TVM_ALWAYS_INLINE std::unique_ptr LogCheck##name(const X& x, const Y& y) { \ + if (x op y) return nullptr; \ + return LogCheckFormat(x, y); \ + } \ + TVM_ALWAYS_INLINE std::unique_ptr LogCheck##name(int x, int y) { \ + return LogCheck##name(x, y); \ } #pragma GCC diagnostic push @@ -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) @@ -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) diff --git a/include/tvm/runtime/packed_func.h b/include/tvm/runtime/packed_func.h index 65f7e7616274..58bd2859c10a 100644 --- a/include/tvm/runtime/packed_func.h +++ b/include/tvm/runtime/packed_func.h @@ -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 { @@ -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_) { @@ -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 diff --git a/src/runtime/logging.cc b/src/runtime/logging.cc index 227814bcddd4..8f0537ad7adc 100644 --- a/src/runtime/logging.cc +++ b/src/runtime/logging.cc @@ -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