| 1 | /* Copyright 2015 The TensorFlow Authors. All Rights Reserved. |
| 2 | |
| 3 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | you may not use this file except in compliance with the License. |
| 5 | You may obtain a copy of the License at |
| 6 | |
| 7 | http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | |
| 9 | Unless required by applicable law or agreed to in writing, software |
| 10 | distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | See the License for the specific language governing permissions and |
| 13 | limitations under the License. |
| 14 | ==============================================================================*/ |
| 15 | |
| 16 | #ifndef TENSORFLOW_PLATFORM_DEFAULT_LOGGING_H_ |
| 17 | #define TENSORFLOW_PLATFORM_DEFAULT_LOGGING_H_ |
| 18 | |
| 19 | // IWYU pragma: private, include "third_party/tensorflow/core/platform/logging.h" |
| 20 | // IWYU pragma: friend third_party/tensorflow/core/platform/logging.h |
| 21 | |
| 22 | #include <limits> |
| 23 | #include <sstream> |
| 24 | #include "tensorflow/core/platform/macros.h" |
| 25 | #include "tensorflow/core/platform/types.h" |
| 26 | |
| 27 | // TODO(mrry): Prevent this Windows.h #define from leaking out of our headers. |
| 28 | #undef ERROR |
| 29 | |
| 30 | namespace tensorflow { |
| 31 | const int INFO = 0; // base_logging::INFO; |
| 32 | const int WARNING = 1; // base_logging::WARNING; |
| 33 | const int ERROR = 2; // base_logging::ERROR; |
| 34 | const int FATAL = 3; // base_logging::FATAL; |
| 35 | const int NUM_SEVERITIES = 4; // base_logging::NUM_SEVERITIES; |
| 36 | |
| 37 | namespace internal { |
| 38 | |
| 39 | class LogMessage : public std::basic_ostringstream<char> { |
| 40 | public: |
| 41 | LogMessage(const char* fname, int line, int severity); |
| 42 | ~LogMessage(); |
| 43 | |
| 44 | // Returns the minimum log level for VLOG statements. |
| 45 | // E.g., if MinVLogLevel() is 2, then VLOG(2) statements will produce output, |
| 46 | // but VLOG(3) will not. Defaults to 0. |
| 47 | static int64 MinVLogLevel(); |
| 48 | |
| 49 | protected: |
| 50 | void GenerateLogMessage(); |
| 51 | |
| 52 | private: |
| 53 | const char* fname_; |
| 54 | int line_; |
| 55 | int severity_; |
| 56 | }; |
| 57 | |
| 58 | // LogMessageFatal ensures the process will exit in failure after |
| 59 | // logging this message. |
| 60 | class LogMessageFatal : public LogMessage { |
| 61 | public: |
| 62 | LogMessageFatal(const char* file, int line) TF_ATTRIBUTE_COLD; |
| 63 | TF_ATTRIBUTE_NORETURN ~LogMessageFatal(); |
| 64 | }; |
| 65 | |
| 66 | #define _TF_LOG_INFO \ |
| 67 | ::tensorflow::internal::LogMessage(__FILE__, __LINE__, ::tensorflow::INFO) |
| 68 | #define _TF_LOG_WARNING \ |
| 69 | ::tensorflow::internal::LogMessage(__FILE__, __LINE__, ::tensorflow::WARNING) |
| 70 | #define _TF_LOG_ERROR \ |
| 71 | ::tensorflow::internal::LogMessage(__FILE__, __LINE__, ::tensorflow::ERROR) |
| 72 | #define _TF_LOG_FATAL \ |
| 73 | ::tensorflow::internal::LogMessageFatal(__FILE__, __LINE__) |
| 74 | |
| 75 | #define _TF_LOG_QFATAL _TF_LOG_FATAL |
| 76 | |
| 77 | #define LOG(severity) _TF_LOG_##severity |
| 78 | |
| 79 | #ifdef IS_MOBILE_PLATFORM |
| 80 | // Turn VLOG off when under mobile devices for considerations of binary size. |
| 81 | #define VLOG_IS_ON(lvl) ((lvl) <= 0) |
| 82 | #else |
| 83 | // Otherwise, Set TF_CPP_MIN_VLOG_LEVEL environment to update minimum log level |
| 84 | // of VLOG |
| 85 | #define VLOG_IS_ON(lvl) \ |
| 86 | ((lvl) <= ::tensorflow::internal::LogMessage::MinVLogLevel()) |
| 87 | #endif |
| 88 | |
| 89 | #define VLOG(lvl) \ |
| 90 | if (TF_PREDICT_FALSE(VLOG_IS_ON(lvl))) \ |
| 91 | ::tensorflow::internal::LogMessage(__FILE__, __LINE__, tensorflow::INFO) |
| 92 | |
| 93 | // CHECK dies with a fatal error if condition is not true. It is *not* |
| 94 | // controlled by NDEBUG, so the check will be executed regardless of |
| 95 | // compilation mode. Therefore, it is safe to do things like: |
| 96 | // CHECK(fp->Write(x) == 4) |
| 97 | #define CHECK(condition) \ |
| 98 | if (TF_PREDICT_FALSE(!(condition))) \ |
| 99 | LOG(FATAL) << "Check failed: " #condition " " |
| 100 | |
| 101 | // Function is overloaded for integral types to allow static const |
| 102 | // integrals declared in classes and not defined to be used as arguments to |
| 103 | // CHECK* macros. It's not encouraged though. |
| 104 | template <typename T> |
| 105 | inline const T& GetReferenceableValue(const T& t) { |
| 106 | return t; |
| 107 | } |
| 108 | inline char GetReferenceableValue(char t) { return t; } |
| 109 | inline unsigned char GetReferenceableValue(unsigned char t) { return t; } |
| 110 | inline signed char GetReferenceableValue(signed char t) { return t; } |
| 111 | inline short GetReferenceableValue(short t) { return t; } |
| 112 | inline unsigned short GetReferenceableValue(unsigned short t) { return t; } |
| 113 | inline int GetReferenceableValue(int t) { return t; } |
| 114 | inline unsigned int GetReferenceableValue(unsigned int t) { return t; } |
| 115 | inline long GetReferenceableValue(long t) { return t; } |
| 116 | inline unsigned long GetReferenceableValue(unsigned long t) { return t; } |
| 117 | inline long long GetReferenceableValue(long long t) { return t; } |
| 118 | inline unsigned long long GetReferenceableValue(unsigned long long t) { |
| 119 | return t; |
| 120 | } |
| 121 | |
| 122 | // This formats a value for a failing CHECK_XX statement. Ordinarily, |
| 123 | // it uses the definition for operator<<, with a few special cases below. |
| 124 | template <typename T> |
| 125 | inline void MakeCheckOpValueString(std::ostream* os, const T& v) { |
| 126 | (*os) << v; |
| 127 | } |
| 128 | |
| 129 | // Overrides for char types provide readable values for unprintable |
| 130 | // characters. |
| 131 | template <> |
| 132 | void MakeCheckOpValueString(std::ostream* os, const char& v); |
| 133 | template <> |
| 134 | void MakeCheckOpValueString(std::ostream* os, const signed char& v); |
| 135 | template <> |
| 136 | void MakeCheckOpValueString(std::ostream* os, const unsigned char& v); |
| 137 | |
| 138 | #if LANG_CXX11 |
| 139 | // We need an explicit specialization for std::nullptr_t. |
| 140 | template <> |
| 141 | void MakeCheckOpValueString(std::ostream* os, const std::nullptr_t& p); |
| 142 | #endif |
| 143 | |
| 144 | // A container for a string pointer which can be evaluated to a bool - |
| 145 | // true iff the pointer is non-NULL. |
| 146 | struct CheckOpString { |
| 147 | CheckOpString(string* str) : str_(str) {} |
| 148 | // No destructor: if str_ is non-NULL, we're about to LOG(FATAL), |
| 149 | // so there's no point in cleaning up str_. |
| 150 | operator bool() const { return TF_PREDICT_FALSE(str_ != NULL); } |
| 151 | string* str_; |
| 152 | }; |
| 153 | |
| 154 | // Build the error message string. Specify no inlining for code size. |
| 155 | template <typename T1, typename T2> |
| 156 | string* MakeCheckOpString(const T1& v1, const T2& v2, |
| 157 | const char* exprtext) TF_ATTRIBUTE_NOINLINE; |
| 158 | |
| 159 | // A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX |
| 160 | // statement. See MakeCheckOpString for sample usage. Other |
| 161 | // approaches were considered: use of a template method (e.g., |
| 162 | // base::BuildCheckOpString(exprtext, base::Print<T1>, &v1, |
| 163 | // base::Print<T2>, &v2), however this approach has complications |
| 164 | // related to volatile arguments and function-pointer arguments). |
| 165 | class CheckOpMessageBuilder { |
| 166 | public: |
| 167 | // Inserts "exprtext" and " (" to the stream. |
| 168 | explicit CheckOpMessageBuilder(const char* exprtext); |
| 169 | // Deletes "stream_". |
| 170 | ~CheckOpMessageBuilder(); |
| 171 | // For inserting the first variable. |
| 172 | std::ostream* ForVar1() { return stream_; } |
| 173 | // For inserting the second variable (adds an intermediate " vs. "). |
| 174 | std::ostream* ForVar2(); |
| 175 | // Get the result (inserts the closing ")"). |
| 176 | string* NewString(); |
| 177 | |
| 178 | private: |
| 179 | std::ostringstream* stream_; |
| 180 | }; |
| 181 | |
| 182 | template <typename T1, typename T2> |
| 183 | string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) { |
| 184 | CheckOpMessageBuilder comb(exprtext); |
| 185 | MakeCheckOpValueString(comb.ForVar1(), v1); |
| 186 | MakeCheckOpValueString(comb.ForVar2(), v2); |
| 187 | return comb.NewString(); |
| 188 | } |
| 189 | |
| 190 | // Helper functions for CHECK_OP macro. |
| 191 | // The (int, int) specialization works around the issue that the compiler |
| 192 | // will not instantiate the template version of the function on values of |
| 193 | // unnamed enum type - see comment below. |
| 194 | // The (size_t, int) and (int, size_t) specialization are to handle unsigned |
| 195 | // comparison errors while still being thorough with the comparison. |
| 196 | #define TF_DEFINE_CHECK_OP_IMPL(name, op) \ |
| 197 | template <typename T1, typename T2> \ |
| 198 | inline string* name##Impl(const T1& v1, const T2& v2, \ |
| 199 | const char* exprtext) { \ |
| 200 | if (TF_PREDICT_TRUE(v1 op v2)) \ |
| 201 | return NULL; \ |
| 202 | else \ |
| 203 | return ::tensorflow::internal::MakeCheckOpString(v1, v2, exprtext); \ |
| 204 | } \ |
| 205 | inline string* name##Impl(int v1, int v2, const char* exprtext) { \ |
| 206 | return name##Impl<int, int>(v1, v2, exprtext); \ |
| 207 | } \ |
| 208 | inline string* name##Impl(const size_t v1, const int v2, \ |
| 209 | const char* exprtext) { \ |
| 210 | if (TF_PREDICT_FALSE(v2 < 0)) { \ |
| 211 | return ::tensorflow::internal::MakeCheckOpString(v1, v2, exprtext); \ |
| 212 | } \ |
| 213 | const size_t uval = (size_t)((unsigned)v1); \ |
| 214 | return name##Impl<size_t, size_t>(uval, v2, exprtext); \ |
| 215 | } \ |
| 216 | inline string* name##Impl(const int v1, const size_t v2, \ |
| 217 | const char* exprtext) { \ |
| 218 | if (TF_PREDICT_FALSE(v2 >= std::numeric_limits<int>::max())) { \ |
| 219 | return ::tensorflow::internal::MakeCheckOpString(v1, v2, exprtext); \ |
| 220 | } \ |
| 221 | const size_t uval = (size_t)((unsigned)v2); \ |
| 222 | return name##Impl<size_t, size_t>(v1, uval, exprtext); \ |
| 223 | } |
| 224 | |
| 225 | // We use the full name Check_EQ, Check_NE, etc. in case the file including |
| 226 | // base/logging.h provides its own #defines for the simpler names EQ, NE, etc. |
| 227 | // This happens if, for example, those are used as token names in a |
| 228 | // yacc grammar. |
| 229 | TF_DEFINE_CHECK_OP_IMPL(Check_EQ, |
| 230 | ==) // Compilation error with CHECK_EQ(NULL, x)? |
| 231 | TF_DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead. |
| 232 | TF_DEFINE_CHECK_OP_IMPL(Check_LE, <=) |
| 233 | TF_DEFINE_CHECK_OP_IMPL(Check_LT, <) |
| 234 | TF_DEFINE_CHECK_OP_IMPL(Check_GE, >=) |
| 235 | TF_DEFINE_CHECK_OP_IMPL(Check_GT, >) |
| 236 | #undef TF_DEFINE_CHECK_OP_IMPL |
| 237 | |
| 238 | // In optimized mode, use CheckOpString to hint to compiler that |
| 239 | // the while condition is unlikely. |
| 240 | #define CHECK_OP_LOG(name, op, val1, val2) \ |
| 241 | while (::tensorflow::internal::CheckOpString _result = \ |
| 242 | ::tensorflow::internal::name##Impl( \ |
| 243 | ::tensorflow::internal::GetReferenceableValue(val1), \ |
| 244 | ::tensorflow::internal::GetReferenceableValue(val2), \ |
| 245 | #val1 " " #op " " #val2)) \ |
| 246 | ::tensorflow::internal::LogMessageFatal(__FILE__, __LINE__) << *(_result.str_) |
| 247 | |
| 248 | #define CHECK_OP(name, op, val1, val2) CHECK_OP_LOG(name, op, val1, val2) |
| 249 | |
| 250 | // CHECK_EQ/NE/... |
| 251 | #define CHECK_EQ(val1, val2) CHECK_OP(Check_EQ, ==, val1, val2) |
| 252 | #define CHECK_NE(val1, val2) CHECK_OP(Check_NE, !=, val1, val2) |
| 253 | #define CHECK_LE(val1, val2) CHECK_OP(Check_LE, <=, val1, val2) |
| 254 | #define CHECK_LT(val1, val2) CHECK_OP(Check_LT, <, val1, val2) |
| 255 | #define CHECK_GE(val1, val2) CHECK_OP(Check_GE, >=, val1, val2) |
| 256 | #define CHECK_GT(val1, val2) CHECK_OP(Check_GT, >, val1, val2) |
| 257 | #define CHECK_NOTNULL(val) \ |
| 258 | ::tensorflow::internal::CheckNotNull(__FILE__, __LINE__, \ |
| 259 | "'" #val "' Must be non NULL", (val)) |
| 260 | |
| 261 | #ifndef NDEBUG |
| 262 | // DCHECK_EQ/NE/... |
| 263 | #define DCHECK(condition) CHECK(condition) |
| 264 | #define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2) |
| 265 | #define DCHECK_NE(val1, val2) CHECK_NE(val1, val2) |
| 266 | #define DCHECK_LE(val1, val2) CHECK_LE(val1, val2) |
| 267 | #define DCHECK_LT(val1, val2) CHECK_LT(val1, val2) |
| 268 | #define DCHECK_GE(val1, val2) CHECK_GE(val1, val2) |
| 269 | #define DCHECK_GT(val1, val2) CHECK_GT(val1, val2) |
| 270 | |
| 271 | #else |
| 272 | |
| 273 | #define DCHECK(condition) \ |
| 274 | while (false && (condition)) LOG(FATAL) |
| 275 | |
| 276 | // NDEBUG is defined, so DCHECK_EQ(x, y) and so on do nothing. |
| 277 | // However, we still want the compiler to parse x and y, because |
| 278 | // we don't want to lose potentially useful errors and warnings. |
| 279 | // _DCHECK_NOP is a helper, and should not be used outside of this file. |
| 280 | #define _TF_DCHECK_NOP(x, y) \ |
| 281 | while (false && ((void)(x), (void)(y), 0)) LOG(FATAL) |
| 282 | |
| 283 | #define DCHECK_EQ(x, y) _TF_DCHECK_NOP(x, y) |
| 284 | #define DCHECK_NE(x, y) _TF_DCHECK_NOP(x, y) |
| 285 | #define DCHECK_LE(x, y) _TF_DCHECK_NOP(x, y) |
| 286 | #define DCHECK_LT(x, y) _TF_DCHECK_NOP(x, y) |
| 287 | #define DCHECK_GE(x, y) _TF_DCHECK_NOP(x, y) |
| 288 | #define DCHECK_GT(x, y) _TF_DCHECK_NOP(x, y) |
| 289 | |
| 290 | #endif |
| 291 | |
| 292 | // These are for when you don't want a CHECK failure to print a verbose |
| 293 | // stack trace. The implementation of CHECK* in this file already doesn't. |
| 294 | #define QCHECK(condition) CHECK(condition) |
| 295 | #define QCHECK_EQ(x, y) CHECK_EQ(x, y) |
| 296 | #define QCHECK_NE(x, y) CHECK_NE(x, y) |
| 297 | #define QCHECK_LE(x, y) CHECK_LE(x, y) |
| 298 | #define QCHECK_LT(x, y) CHECK_LT(x, y) |
| 299 | #define QCHECK_GE(x, y) CHECK_GE(x, y) |
| 300 | #define QCHECK_GT(x, y) CHECK_GT(x, y) |
| 301 | |
| 302 | template <typename T> |
| 303 | T&& CheckNotNull(const char* file, int line, const char* exprtext, T&& t) { |
| 304 | if (t == nullptr) { |
| 305 | LogMessageFatal(file, line) << string(exprtext); |
| 306 | } |
| 307 | return std::forward<T>(t); |
| 308 | } |
| 309 | |
| 310 | int64 MinLogLevelFromEnv(); |
| 311 | |
| 312 | int64 MinVLogLevelFromEnv(); |
| 313 | |
| 314 | } // namespace internal |
| 315 | } // namespace tensorflow |
| 316 | |
| 317 | #endif // TENSORFLOW_PLATFORM_DEFAULT_LOGGING_H_ |
| 318 | |