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 | |