diff options
Diffstat (limited to 'tensorflow/core/platform/default/logging.h')
-rw-r--r-- | tensorflow/core/platform/default/logging.h | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/tensorflow/core/platform/default/logging.h b/tensorflow/core/platform/default/logging.h new file mode 100644 index 0000000000..034178751e --- /dev/null +++ b/tensorflow/core/platform/default/logging.h @@ -0,0 +1,258 @@ +#ifndef TENSORFLOW_PLATFORM_DEFAULT_LOGGING_H_ +#define TENSORFLOW_PLATFORM_DEFAULT_LOGGING_H_ + +#include <sstream> +#include "tensorflow/core/platform/port.h" + +namespace tensorflow { +const int INFO = 0; // base_logging::INFO; +const int WARNING = 1; // base_logging::WARNING; +const int ERROR = 2; // base_logging::ERROR; +const int FATAL = 3; // base_logging::FATAL; +const int NUM_SEVERITIES = 4; // base_logging::NUM_SEVERITIES; + +namespace internal { + +class LogMessage : public std::basic_ostringstream<char> { + public: + LogMessage(const char* fname, int line, int severity); + ~LogMessage(); + + protected: + void GenerateLogMessage(); + + private: + const char* fname_; + int line_; + int severity_; +}; + +// LogMessageFatal ensures the process will exit in failure after +// logging this message. +class LogMessageFatal : public LogMessage { + public: + LogMessageFatal(const char* file, int line) TF_ATTRIBUTE_COLD; + ~LogMessageFatal() TF_ATTRIBUTE_NORETURN; +}; + +#define _TF_LOG_INFO \ + ::tensorflow::internal::LogMessage(__FILE__, __LINE__, tensorflow::INFO) +#define _TF_LOG_WARNING \ + ::tensorflow::internal::LogMessage(__FILE__, __LINE__, tensorflow::WARNING) +#define _TF_LOG_ERROR \ + ::tensorflow::internal::LogMessage(__FILE__, __LINE__, tensorflow::ERROR) +#define _TF_LOG_FATAL \ + ::tensorflow::internal::LogMessageFatal(__FILE__, __LINE__) + +#define LOG(severity) _TF_LOG_##severity + +// TODO(jeff): Define a proper implementation of VLOG_IS_ON +#define VLOG_IS_ON(lvl) ((lvl) <= 0) + +#define VLOG(lvl) \ + if (VLOG_IS_ON(lvl)) \ + ::tensorflow::internal::LogMessage(__FILE__, __LINE__, tensorflow::INFO) + +// CHECK dies with a fatal error if condition is not true. It is *not* +// controlled by NDEBUG, so the check will be executed regardless of +// compilation mode. Therefore, it is safe to do things like: +// CHECK(fp->Write(x) == 4) +#define CHECK(condition) \ + if (TF_PREDICT_FALSE(!(condition))) \ + LOG(FATAL) << "Check failed: " #condition " " + +// Function is overloaded for integral types to allow static const +// integrals declared in classes and not defined to be used as arguments to +// CHECK* macros. It's not encouraged though. +template <typename T> +inline const T& GetReferenceableValue(const T& t) { + return t; +} +inline char GetReferenceableValue(char t) { return t; } +inline unsigned char GetReferenceableValue(unsigned char t) { return t; } +inline signed char GetReferenceableValue(signed char t) { return t; } +inline short GetReferenceableValue(short t) { return t; } +inline unsigned short GetReferenceableValue(unsigned short t) { return t; } +inline int GetReferenceableValue(int t) { return t; } +inline unsigned int GetReferenceableValue(unsigned int t) { return t; } +inline long GetReferenceableValue(long t) { return t; } +inline unsigned long GetReferenceableValue(unsigned long t) { return t; } +inline long long GetReferenceableValue(long long t) { return t; } +inline unsigned long long GetReferenceableValue(unsigned long long t) { + return t; +} + +// This formats a value for a failing CHECK_XX statement. Ordinarily, +// it uses the definition for operator<<, with a few special cases below. +template <typename T> +inline void MakeCheckOpValueString(std::ostream* os, const T& v) { + (*os) << v; +} + +// Overrides for char types provide readable values for unprintable +// characters. +template <> +void MakeCheckOpValueString(std::ostream* os, const char& v); +template <> +void MakeCheckOpValueString(std::ostream* os, const signed char& v); +template <> +void MakeCheckOpValueString(std::ostream* os, const unsigned char& v); + +#if LANG_CXX11 +// We need an explicit specialization for std::nullptr_t. +template <> +void MakeCheckOpValueString(std::ostream* os, const std::nullptr_t& p); +#endif + +// A container for a string pointer which can be evaluated to a bool - +// true iff the pointer is non-NULL. +struct CheckOpString { + CheckOpString(string* str) : str_(str) {} + // No destructor: if str_ is non-NULL, we're about to LOG(FATAL), + // so there's no point in cleaning up str_. + operator bool() const { return TF_PREDICT_FALSE(str_ != NULL); } + string* str_; +}; + +// Build the error message string. Specify no inlining for code size. +template <typename T1, typename T2> +string* MakeCheckOpString(const T1& v1, const T2& v2, + const char* exprtext) TF_ATTRIBUTE_NOINLINE; + +// A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX +// statement. See MakeCheckOpString for sample usage. Other +// approaches were considered: use of a template method (e.g., +// base::BuildCheckOpString(exprtext, base::Print<T1>, &v1, +// base::Print<T2>, &v2), however this approach has complications +// related to volatile arguments and function-pointer arguments). +class CheckOpMessageBuilder { + public: + // Inserts "exprtext" and " (" to the stream. + explicit CheckOpMessageBuilder(const char* exprtext); + // Deletes "stream_". + ~CheckOpMessageBuilder(); + // For inserting the first variable. + std::ostream* ForVar1() { return stream_; } + // For inserting the second variable (adds an intermediate " vs. "). + std::ostream* ForVar2(); + // Get the result (inserts the closing ")"). + string* NewString(); + + private: + std::ostringstream* stream_; +}; + +template <typename T1, typename T2> +string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) { + CheckOpMessageBuilder comb(exprtext); + MakeCheckOpValueString(comb.ForVar1(), v1); + MakeCheckOpValueString(comb.ForVar2(), v2); + return comb.NewString(); +} + +// Helper functions for CHECK_OP macro. +// The (int, int) specialization works around the issue that the compiler +// will not instantiate the template version of the function on values of +// unnamed enum type - see comment below. +#define TF_DEFINE_CHECK_OP_IMPL(name, op) \ + template <typename T1, typename T2> \ + inline string* name##Impl(const T1& v1, const T2& v2, \ + const char* exprtext) { \ + if (TF_PREDICT_TRUE(v1 op v2)) \ + return NULL; \ + else \ + return ::tensorflow::internal::MakeCheckOpString(v1, v2, exprtext); \ + } \ + inline string* name##Impl(int v1, int v2, const char* exprtext) { \ + return name##Impl<int, int>(v1, v2, exprtext); \ + } + +// We use the full name Check_EQ, Check_NE, etc. in case the file including +// base/logging.h provides its own #defines for the simpler names EQ, NE, etc. +// This happens if, for example, those are used as token names in a +// yacc grammar. +TF_DEFINE_CHECK_OP_IMPL(Check_EQ, + == ) // Compilation error with CHECK_EQ(NULL, x)? +TF_DEFINE_CHECK_OP_IMPL(Check_NE, != ) // Use CHECK(x == NULL) instead. +TF_DEFINE_CHECK_OP_IMPL(Check_LE, <= ) +TF_DEFINE_CHECK_OP_IMPL(Check_LT, < ) +TF_DEFINE_CHECK_OP_IMPL(Check_GE, >= ) +TF_DEFINE_CHECK_OP_IMPL(Check_GT, > ) +#undef TF_DEFINE_CHECK_OP_IMPL + +// In optimized mode, use CheckOpString to hint to compiler that +// the while condition is unlikely. +#define CHECK_OP_LOG(name, op, val1, val2) \ + while (::tensorflow::internal::CheckOpString _result = \ + ::tensorflow::internal::name##Impl( \ + ::tensorflow::internal::GetReferenceableValue(val1), \ + ::tensorflow::internal::GetReferenceableValue(val2), \ + #val1 " " #op " " #val2)) \ + ::tensorflow::internal::LogMessageFatal(__FILE__, __LINE__) << *(_result.str_) + +#define CHECK_OP(name, op, val1, val2) CHECK_OP_LOG(name, op, val1, val2) + +// CHECK_EQ/NE/... +#define CHECK_EQ(val1, val2) CHECK_OP(Check_EQ, ==, val1, val2) +#define CHECK_NE(val1, val2) CHECK_OP(Check_NE, !=, val1, val2) +#define CHECK_LE(val1, val2) CHECK_OP(Check_LE, <=, val1, val2) +#define CHECK_LT(val1, val2) CHECK_OP(Check_LT, <, val1, val2) +#define CHECK_GE(val1, val2) CHECK_OP(Check_GE, >=, val1, val2) +#define CHECK_GT(val1, val2) CHECK_OP(Check_GT, >, val1, val2) +#define CHECK_NOTNULL(val) \ + ::tensorflow::internal::CheckNotNull(__FILE__, __LINE__, \ + "'" #val "' Must be non NULL", (val)) + +#ifndef NDEBUG +// DCHECK_EQ/NE/... +#define DCHECK(condition) CHECK(condition) +#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2) +#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2) +#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2) +#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2) +#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2) +#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2) + +#else + +#define DCHECK(condition) \ + while (false && (condition)) LOG(FATAL) + +// NDEBUG is defined, so DCHECK_EQ(x, y) and so on do nothing. +// However, we still want the compiler to parse x and y, because +// we don't want to lose potentially useful errors and warnings. +// _DCHECK_NOP is a helper, and should not be used outside of this file. +#define _TF_DCHECK_NOP(x, y) \ + while (false && ((void)(x), (void)(y), 0)) LOG(FATAL) + +#define DCHECK_EQ(x, y) _TF_DCHECK_NOP(x, y) +#define DCHECK_NE(x, y) _TF_DCHECK_NOP(x, y) +#define DCHECK_LE(x, y) _TF_DCHECK_NOP(x, y) +#define DCHECK_LT(x, y) _TF_DCHECK_NOP(x, y) +#define DCHECK_GE(x, y) _TF_DCHECK_NOP(x, y) +#define DCHECK_GT(x, y) _TF_DCHECK_NOP(x, y) + +#endif + +// These are for when you don't want a CHECK failure to print a verbose +// stack trace. The implementation of CHECK* in this file already doesn't. +#define QCHECK(condition) CHECK(condition) +#define QCHECK_EQ(x, y) CHECK_EQ(x, y) +#define QCHECK_NE(x, y) CHECK_NE(x, y) +#define QCHECK_LE(x, y) CHECK_LE(x, y) +#define QCHECK_LT(x, y) CHECK_LT(x, y) +#define QCHECK_GE(x, y) CHECK_GE(x, y) +#define QCHECK_GT(x, y) CHECK_GT(x, y) + +template <typename T> +T&& CheckNotNull(const char* file, int line, const char* exprtext, T&& t) { + if (t == nullptr) { + LogMessageFatal(file, line) << string(exprtext); + } + return std::forward<T>(t); +} + +} // namespace internal +} // namespace tensorflow + +#endif // TENSORFLOW_PLATFORM_DEFAULT_LOGGING_H_ |