Skip to content

Commit

Permalink
[Logging] Bring back the stack size optimization (apache#7756)
Browse files Browse the repository at this point in the history
  • Loading branch information
junrushao authored and Trevor Morris committed May 6, 2021
1 parent c5288b4 commit 0ee85f3
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 39 deletions.
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

0 comments on commit 0ee85f3

Please sign in to comment.