• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_CORE_PLATFORM_DEFAULT_LOGGING_H_
17 #define TENSORFLOW_CORE_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   // Returns whether VLOG level lvl is activated for the file fname.
50   //
51   // E.g. if the environment variable TF_CPP_VMODULE contains foo=3 and fname is
52   // foo.cc and lvl is <= 3, this will return true. It will also return true if
53   // the level is lower or equal to TF_CPP_MIN_VLOG_LEVEL (default zero).
54   //
55   // It is expected that the result of this query will be cached in the VLOG-ing
56   // call site to avoid repeated lookups. This routine performs a hash-map
57   // access against the VLOG-ing specification provided by the env var.
58   static bool VmoduleActivated(const char* fname, int level);
59 
60  protected:
61   void GenerateLogMessage();
62 
63  private:
64   const char* fname_;
65   int line_;
66   int severity_;
67 };
68 
69 // Uses the lower operator & precedence to voidify a LogMessage reference, so
70 // that the ternary VLOG() implementation is balanced, type wise.
71 struct Voidifier {
72   template <typename T>
73   void operator&(const T&)const {}
74 };
75 
76 // LogMessageFatal ensures the process will exit in failure after
77 // logging this message.
78 class LogMessageFatal : public LogMessage {
79  public:
80   LogMessageFatal(const char* file, int line) TF_ATTRIBUTE_COLD;
81   TF_ATTRIBUTE_NORETURN ~LogMessageFatal();
82 };
83 
84 #define _TF_LOG_INFO \
85   ::tensorflow::internal::LogMessage(__FILE__, __LINE__, ::tensorflow::INFO)
86 #define _TF_LOG_WARNING \
87   ::tensorflow::internal::LogMessage(__FILE__, __LINE__, ::tensorflow::WARNING)
88 #define _TF_LOG_ERROR \
89   ::tensorflow::internal::LogMessage(__FILE__, __LINE__, ::tensorflow::ERROR)
90 #define _TF_LOG_FATAL \
91   ::tensorflow::internal::LogMessageFatal(__FILE__, __LINE__)
92 
93 #define _TF_LOG_QFATAL _TF_LOG_FATAL
94 
95 #define LOG(severity) _TF_LOG_##severity
96 
97 #ifdef IS_MOBILE_PLATFORM
98 
99 // Turn VLOG off when under mobile devices for considerations of binary size.
100 #define VLOG_IS_ON(lvl) ((lvl) <= 0)
101 
102 #else
103 
104 // Otherwise, set TF_CPP_MIN_VLOG_LEVEL environment to update minimum log level
105 // of VLOG, or TF_CPP_VMODULE to set the minimum log level for individual
106 // translation units.
107 #define VLOG_IS_ON(lvl)                                                     \
108   (([](int level, const char* fname) {                                      \
109     static const bool vmodule_activated =                                   \
110         ::tensorflow::internal::LogMessage::VmoduleActivated(fname, level); \
111     return vmodule_activated;                                               \
112   })(lvl, __FILE__))
113 
114 #endif
115 
116 #define VLOG(level)                                              \
117   TF_PREDICT_TRUE(!VLOG_IS_ON(level))                            \
118   ? (void)0                                                      \
119   : ::tensorflow::internal::Voidifier() &                        \
120           ::tensorflow::internal::LogMessage(__FILE__, __LINE__, \
121                                              tensorflow::INFO)
122 
123 // CHECK dies with a fatal error if condition is not true.  It is *not*
124 // controlled by NDEBUG, so the check will be executed regardless of
125 // compilation mode.  Therefore, it is safe to do things like:
126 //    CHECK(fp->Write(x) == 4)
127 #define CHECK(condition)              \
128   if (TF_PREDICT_FALSE(!(condition))) \
129   LOG(FATAL) << "Check failed: " #condition " "
130 
131 // Function is overloaded for integral types to allow static const
132 // integrals declared in classes and not defined to be used as arguments to
133 // CHECK* macros. It's not encouraged though.
134 template <typename T>
GetReferenceableValue(const T & t)135 inline const T& GetReferenceableValue(const T& t) {
136   return t;
137 }
GetReferenceableValue(char t)138 inline char GetReferenceableValue(char t) { return t; }
GetReferenceableValue(unsigned char t)139 inline unsigned char GetReferenceableValue(unsigned char t) { return t; }
GetReferenceableValue(signed char t)140 inline signed char GetReferenceableValue(signed char t) { return t; }
GetReferenceableValue(short t)141 inline short GetReferenceableValue(short t) { return t; }
GetReferenceableValue(unsigned short t)142 inline unsigned short GetReferenceableValue(unsigned short t) { return t; }
GetReferenceableValue(int t)143 inline int GetReferenceableValue(int t) { return t; }
GetReferenceableValue(unsigned int t)144 inline unsigned int GetReferenceableValue(unsigned int t) { return t; }
GetReferenceableValue(long t)145 inline long GetReferenceableValue(long t) { return t; }
GetReferenceableValue(unsigned long t)146 inline unsigned long GetReferenceableValue(unsigned long t) { return t; }
GetReferenceableValue(long long t)147 inline long long GetReferenceableValue(long long t) { return t; }
GetReferenceableValue(unsigned long long t)148 inline unsigned long long GetReferenceableValue(unsigned long long t) {
149   return t;
150 }
151 
152 // This formats a value for a failing CHECK_XX statement.  Ordinarily,
153 // it uses the definition for operator<<, with a few special cases below.
154 template <typename T>
MakeCheckOpValueString(std::ostream * os,const T & v)155 inline void MakeCheckOpValueString(std::ostream* os, const T& v) {
156   (*os) << v;
157 }
158 
159 // Overrides for char types provide readable values for unprintable
160 // characters.
161 template <>
162 void MakeCheckOpValueString(std::ostream* os, const char& v);
163 template <>
164 void MakeCheckOpValueString(std::ostream* os, const signed char& v);
165 template <>
166 void MakeCheckOpValueString(std::ostream* os, const unsigned char& v);
167 
168 #if LANG_CXX11
169 // We need an explicit specialization for std::nullptr_t.
170 template <>
171 void MakeCheckOpValueString(std::ostream* os, const std::nullptr_t& p);
172 #endif
173 
174 // A container for a string pointer which can be evaluated to a bool -
175 // true iff the pointer is non-NULL.
176 struct CheckOpString {
CheckOpStringCheckOpString177   CheckOpString(string* str) : str_(str) {}
178   // No destructor: if str_ is non-NULL, we're about to LOG(FATAL),
179   // so there's no point in cleaning up str_.
180   operator bool() const { return TF_PREDICT_FALSE(str_ != NULL); }
181   string* str_;
182 };
183 
184 // Build the error message string. Specify no inlining for code size.
185 template <typename T1, typename T2>
186 string* MakeCheckOpString(const T1& v1, const T2& v2,
187                           const char* exprtext) TF_ATTRIBUTE_NOINLINE;
188 
189 // A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX
190 // statement.  See MakeCheckOpString for sample usage.  Other
191 // approaches were considered: use of a template method (e.g.,
192 // base::BuildCheckOpString(exprtext, base::Print<T1>, &v1,
193 // base::Print<T2>, &v2), however this approach has complications
194 // related to volatile arguments and function-pointer arguments).
195 class CheckOpMessageBuilder {
196  public:
197   // Inserts "exprtext" and " (" to the stream.
198   explicit CheckOpMessageBuilder(const char* exprtext);
199   // Deletes "stream_".
200   ~CheckOpMessageBuilder();
201   // For inserting the first variable.
ForVar1()202   std::ostream* ForVar1() { return stream_; }
203   // For inserting the second variable (adds an intermediate " vs. ").
204   std::ostream* ForVar2();
205   // Get the result (inserts the closing ")").
206   string* NewString();
207 
208  private:
209   std::ostringstream* stream_;
210 };
211 
212 template <typename T1, typename T2>
MakeCheckOpString(const T1 & v1,const T2 & v2,const char * exprtext)213 string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) {
214   CheckOpMessageBuilder comb(exprtext);
215   MakeCheckOpValueString(comb.ForVar1(), v1);
216   MakeCheckOpValueString(comb.ForVar2(), v2);
217   return comb.NewString();
218 }
219 
220 // Helper functions for CHECK_OP macro.
221 // The (int, int) specialization works around the issue that the compiler
222 // will not instantiate the template version of the function on values of
223 // unnamed enum type - see comment below.
224 // The (size_t, int) and (int, size_t) specialization are to handle unsigned
225 // comparison errors while still being thorough with the comparison.
226 #define TF_DEFINE_CHECK_OP_IMPL(name, op)                                 \
227   template <typename T1, typename T2>                                     \
228   inline string* name##Impl(const T1& v1, const T2& v2,                   \
229                             const char* exprtext) {                       \
230     if (TF_PREDICT_TRUE(v1 op v2))                                        \
231       return NULL;                                                        \
232     else                                                                  \
233       return ::tensorflow::internal::MakeCheckOpString(v1, v2, exprtext); \
234   }                                                                       \
235   inline string* name##Impl(int v1, int v2, const char* exprtext) {       \
236     return name##Impl<int, int>(v1, v2, exprtext);                        \
237   }                                                                       \
238   inline string* name##Impl(const size_t v1, const int v2,                \
239                             const char* exprtext) {                       \
240     if (TF_PREDICT_FALSE(v2 < 0)) {                                       \
241       return ::tensorflow::internal::MakeCheckOpString(v1, v2, exprtext); \
242     }                                                                     \
243     return name##Impl<size_t, size_t>(v1, v2, exprtext);                  \
244   }                                                                       \
245   inline string* name##Impl(const int v1, const size_t v2,                \
246                             const char* exprtext) {                       \
247     if (TF_PREDICT_FALSE(v2 >= std::numeric_limits<int>::max())) {        \
248       return ::tensorflow::internal::MakeCheckOpString(v1, v2, exprtext); \
249     }                                                                     \
250     const size_t uval = (size_t)((unsigned)v2);                           \
251     return name##Impl<size_t, size_t>(v1, uval, exprtext);                \
252   }
253 
254 // We use the full name Check_EQ, Check_NE, etc. in case the file including
255 // base/logging.h provides its own #defines for the simpler names EQ, NE, etc.
256 // This happens if, for example, those are used as token names in a
257 // yacc grammar.
258 TF_DEFINE_CHECK_OP_IMPL(Check_EQ,
259                         ==)  // Compilation error with CHECK_EQ(NULL, x)?
260 TF_DEFINE_CHECK_OP_IMPL(Check_NE, !=)  // Use CHECK(x == NULL) instead.
261 TF_DEFINE_CHECK_OP_IMPL(Check_LE, <=)
262 TF_DEFINE_CHECK_OP_IMPL(Check_LT, <)
263 TF_DEFINE_CHECK_OP_IMPL(Check_GE, >=)
264 TF_DEFINE_CHECK_OP_IMPL(Check_GT, >)
265 #undef TF_DEFINE_CHECK_OP_IMPL
266 
267 // In optimized mode, use CheckOpString to hint to compiler that
268 // the while condition is unlikely.
269 #define CHECK_OP_LOG(name, op, val1, val2)                            \
270   while (::tensorflow::internal::CheckOpString _result =              \
271              ::tensorflow::internal::name##Impl(                      \
272                  ::tensorflow::internal::GetReferenceableValue(val1), \
273                  ::tensorflow::internal::GetReferenceableValue(val2), \
274                  #val1 " " #op " " #val2))                            \
275   ::tensorflow::internal::LogMessageFatal(__FILE__, __LINE__) << *(_result.str_)
276 
277 #define CHECK_OP(name, op, val1, val2) CHECK_OP_LOG(name, op, val1, val2)
278 
279 // CHECK_EQ/NE/...
280 #define CHECK_EQ(val1, val2) CHECK_OP(Check_EQ, ==, val1, val2)
281 #define CHECK_NE(val1, val2) CHECK_OP(Check_NE, !=, val1, val2)
282 #define CHECK_LE(val1, val2) CHECK_OP(Check_LE, <=, val1, val2)
283 #define CHECK_LT(val1, val2) CHECK_OP(Check_LT, <, val1, val2)
284 #define CHECK_GE(val1, val2) CHECK_OP(Check_GE, >=, val1, val2)
285 #define CHECK_GT(val1, val2) CHECK_OP(Check_GT, >, val1, val2)
286 #define CHECK_NOTNULL(val)                                 \
287   ::tensorflow::internal::CheckNotNull(__FILE__, __LINE__, \
288                                        "'" #val "' Must be non NULL", (val))
289 
290 #ifndef NDEBUG
291 // DCHECK_EQ/NE/...
292 #define DCHECK(condition) CHECK(condition)
293 #define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
294 #define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
295 #define DCHECK_LE(val1, val2) CHECK_LE(val1, val2)
296 #define DCHECK_LT(val1, val2) CHECK_LT(val1, val2)
297 #define DCHECK_GE(val1, val2) CHECK_GE(val1, val2)
298 #define DCHECK_GT(val1, val2) CHECK_GT(val1, val2)
299 
300 #else
301 
302 #define DCHECK(condition) \
303   while (false && (condition)) LOG(FATAL)
304 
305 // NDEBUG is defined, so DCHECK_EQ(x, y) and so on do nothing.
306 // However, we still want the compiler to parse x and y, because
307 // we don't want to lose potentially useful errors and warnings.
308 // _DCHECK_NOP is a helper, and should not be used outside of this file.
309 #define _TF_DCHECK_NOP(x, y) \
310   while (false && ((void)(x), (void)(y), 0)) LOG(FATAL)
311 
312 #define DCHECK_EQ(x, y) _TF_DCHECK_NOP(x, y)
313 #define DCHECK_NE(x, y) _TF_DCHECK_NOP(x, y)
314 #define DCHECK_LE(x, y) _TF_DCHECK_NOP(x, y)
315 #define DCHECK_LT(x, y) _TF_DCHECK_NOP(x, y)
316 #define DCHECK_GE(x, y) _TF_DCHECK_NOP(x, y)
317 #define DCHECK_GT(x, y) _TF_DCHECK_NOP(x, y)
318 
319 #endif
320 
321 // These are for when you don't want a CHECK failure to print a verbose
322 // stack trace.  The implementation of CHECK* in this file already doesn't.
323 #define QCHECK(condition) CHECK(condition)
324 #define QCHECK_EQ(x, y) CHECK_EQ(x, y)
325 #define QCHECK_NE(x, y) CHECK_NE(x, y)
326 #define QCHECK_LE(x, y) CHECK_LE(x, y)
327 #define QCHECK_LT(x, y) CHECK_LT(x, y)
328 #define QCHECK_GE(x, y) CHECK_GE(x, y)
329 #define QCHECK_GT(x, y) CHECK_GT(x, y)
330 
331 template <typename T>
CheckNotNull(const char * file,int line,const char * exprtext,T && t)332 T&& CheckNotNull(const char* file, int line, const char* exprtext, T&& t) {
333   if (t == nullptr) {
334     LogMessageFatal(file, line) << string(exprtext);
335   }
336   return std::forward<T>(t);
337 }
338 
339 int64 MinLogLevelFromEnv();
340 
341 int64 MinVLogLevelFromEnv();
342 
343 }  // namespace internal
344 }  // namespace tensorflow
345 
346 #endif  // TENSORFLOW_CORE_PLATFORM_DEFAULT_LOGGING_H_
347