1 #ifndef C10_UTIL_LOGGING_IS_NOT_GOOGLE_GLOG_H_
2 #define C10_UTIL_LOGGING_IS_NOT_GOOGLE_GLOG_H_
3
4 #include <chrono>
5 #include <climits>
6 #include <ctime>
7 #include <iomanip>
8 #include <map>
9 #include <ostream>
10 #include <set>
11 #include <sstream>
12 #include <string>
13 #include <vector>
14
15 #include <c10/util/Flags.h>
16
17 const char CAFFE2_SEVERITY_PREFIX[] = "FEWIV";
18
19 namespace c10 {
20
21 // Log severity level constants.
22 const int GLOG_FATAL = 3;
23 const int GLOG_ERROR = 2;
24 const int GLOG_WARNING = 1;
25 const int GLOG_INFO = 0;
26
27 class C10_API MessageLogger {
28 public:
29 MessageLogger(const char* file, int line, int severity);
30 ~MessageLogger();
31 // Return the stream associated with the logger object.
stream()32 std::stringstream& stream() {
33 return stream_;
34 }
35
36 private:
37 // When there is a fatal log, we simply abort.
DealWithFatal()38 void DealWithFatal() {
39 abort();
40 }
41
42 const char* tag_;
43 std::stringstream stream_;
44 int severity_;
45 };
46
47 // This class is used to explicitly ignore values in the conditional
48 // logging macros. This avoids compiler warnings like "value computed
49 // is not used" and "statement has no effect".
50 class C10_API LoggerVoidify {
51 public:
52 LoggerVoidify() = default;
53 // This has to be an operator with a precedence lower than << but
54 // higher than ?:
55 void operator&(const std::ostream& s [[maybe_unused]]) {}
56 };
57
58 // Log a message and terminate.
59 template <class T>
LogMessageFatal(const char * file,int line,const T & message)60 void LogMessageFatal(const char* file, int line, const T& message) {
61 MessageLogger(file, line, GLOG_FATAL).stream() << message;
62 }
63
64 // Helpers for TORCH_CHECK_NOTNULL(). Two are necessary to support both raw
65 // pointers and smart pointers.
66 template <typename T>
CheckNotNullCommon(const char * file,int line,const char * names,T & t)67 T& CheckNotNullCommon(const char* file, int line, const char* names, T& t) {
68 if (t == nullptr) {
69 LogMessageFatal(file, line, std::string(names));
70 }
71 return t;
72 }
73
74 template <typename T>
CheckNotNull(const char * file,int line,const char * names,T * t)75 T* CheckNotNull(const char* file, int line, const char* names, T* t) {
76 return CheckNotNullCommon(file, line, names, t);
77 }
78
79 template <typename T>
CheckNotNull(const char * file,int line,const char * names,T & t)80 T& CheckNotNull(const char* file, int line, const char* names, T& t) {
81 return CheckNotNullCommon(file, line, names, t);
82 }
83 } // namespace c10
84
85 // ---------------------- Logging Macro definitions --------------------------
86
87 static_assert(
88 CAFFE2_LOG_THRESHOLD <= ::c10::GLOG_FATAL,
89 "CAFFE2_LOG_THRESHOLD should at most be GLOG_FATAL.");
90 // If n is under the compile time caffe log threshold, The _CAFFE_LOG(n)
91 // should not generate anything in optimized code.
92 #define LOG(n) \
93 if (::c10::GLOG_##n >= CAFFE2_LOG_THRESHOLD) \
94 ::c10::MessageLogger(__FILE__, __LINE__, ::c10::GLOG_##n).stream()
95 #define VLOG(n) \
96 if (-n >= CAFFE2_LOG_THRESHOLD) \
97 ::c10::MessageLogger(__FILE__, __LINE__, -n).stream()
98
99 #define LOG_IF(n, condition) \
100 if (::c10::GLOG_##n >= CAFFE2_LOG_THRESHOLD && (condition)) \
101 ::c10::MessageLogger(__FILE__, __LINE__, ::c10::GLOG_##n).stream()
102 #define VLOG_IF(n, condition) \
103 if (-n >= CAFFE2_LOG_THRESHOLD && (condition)) \
104 ::c10::MessageLogger(__FILE__, __LINE__, -n).stream()
105
106 #define VLOG_IS_ON(verboselevel) (CAFFE2_LOG_THRESHOLD <= -(verboselevel))
107
108 // Log with source location information override (to be used in generic
109 // warning/error handlers implemented as functions, not macros)
110 #define LOG_AT_FILE_LINE(n, file, line) \
111 if (::c10::GLOG_##n >= CAFFE2_LOG_THRESHOLD) \
112 ::c10::MessageLogger(file, line, ::c10::GLOG_##n).stream()
113
114 // Log only if condition is met. Otherwise evaluates to void.
115 #define FATAL_IF(condition) \
116 condition ? (void)0 \
117 : ::c10::LoggerVoidify() & \
118 ::c10::MessageLogger(__FILE__, __LINE__, ::c10::GLOG_FATAL).stream()
119
120 // Check for a given boolean condition.
121 #define CHECK(condition) FATAL_IF(condition) << "Check failed: " #condition " "
122
123 #ifndef NDEBUG
124 // Debug only version of CHECK
125 #define DCHECK(condition) FATAL_IF(condition) << "Check failed: " #condition " "
126 #define DLOG(severity) LOG(severity)
127 #else // NDEBUG
128 // Optimized version - generates no code.
129 #define DCHECK(condition) \
130 while (false) \
131 CHECK(condition)
132
133 #define DLOG(n) \
134 true ? (void)0 \
135 : ::c10::LoggerVoidify() & \
136 ::c10::MessageLogger(__FILE__, __LINE__, ::c10::GLOG_##n).stream()
137 #endif // NDEBUG
138
139 #define TORCH_CHECK_OP(val1, val2, op) \
140 FATAL_IF(((val1)op(val2))) << "Check failed: " #val1 " " #op " " #val2 " (" \
141 << (val1) << " vs. " << (val2) << ") "
142
143 // TORCH_CHECK_OP macro definitions
144 #define TORCH_CHECK_EQ(val1, val2) TORCH_CHECK_OP(val1, val2, ==)
145 #define TORCH_CHECK_NE(val1, val2) TORCH_CHECK_OP(val1, val2, !=)
146 #define TORCH_CHECK_LE(val1, val2) TORCH_CHECK_OP(val1, val2, <=)
147 #define TORCH_CHECK_LT(val1, val2) TORCH_CHECK_OP(val1, val2, <)
148 #define TORCH_CHECK_GE(val1, val2) TORCH_CHECK_OP(val1, val2, >=)
149 #define TORCH_CHECK_GT(val1, val2) TORCH_CHECK_OP(val1, val2, >)
150
151 #ifndef NDEBUG
152 // Debug only versions of TORCH_CHECK_OP macros.
153 #define TORCH_DCHECK_EQ(val1, val2) TORCH_CHECK_OP(val1, val2, ==)
154 #define TORCH_DCHECK_NE(val1, val2) TORCH_CHECK_OP(val1, val2, !=)
155 #define TORCH_DCHECK_LE(val1, val2) TORCH_CHECK_OP(val1, val2, <=)
156 #define TORCH_DCHECK_LT(val1, val2) TORCH_CHECK_OP(val1, val2, <)
157 #define TORCH_DCHECK_GE(val1, val2) TORCH_CHECK_OP(val1, val2, >=)
158 #define TORCH_DCHECK_GT(val1, val2) TORCH_CHECK_OP(val1, val2, >)
159 #else // !NDEBUG
160 // These versions generate no code in optimized mode.
161 #define TORCH_DCHECK_EQ(val1, val2) \
162 while (false) \
163 TORCH_CHECK_OP(val1, val2, ==)
164 #define TORCH_DCHECK_NE(val1, val2) \
165 while (false) \
166 TORCH_CHECK_OP(val1, val2, !=)
167 #define TORCH_DCHECK_LE(val1, val2) \
168 while (false) \
169 TORCH_CHECK_OP(val1, val2, <=)
170 #define TORCH_DCHECK_LT(val1, val2) \
171 while (false) \
172 TORCH_CHECK_OP(val1, val2, <)
173 #define TORCH_DCHECK_GE(val1, val2) \
174 while (false) \
175 TORCH_CHECK_OP(val1, val2, >=)
176 #define TORCH_DCHECK_GT(val1, val2) \
177 while (false) \
178 TORCH_CHECK_OP(val1, val2, >)
179 #endif // NDEBUG
180
181 // Check that a pointer is not null.
182 #define TORCH_CHECK_NOTNULL(val) \
183 ::c10::CheckNotNull( \
184 __FILE__, __LINE__, "Check failed: '" #val "' Must be non NULL", (val))
185
186 #ifndef NDEBUG
187 // Debug only version of TORCH_CHECK_NOTNULL
188 #define TORCH_DCHECK_NOTNULL(val) \
189 ::c10::CheckNotNull( \
190 __FILE__, __LINE__, "Check failed: '" #val "' Must be non NULL", (val))
191 #else // !NDEBUG
192 // Optimized version - generates no code.
193 #define TORCH_DCHECK_NOTNULL(val) \
194 while (false) \
195 TORCH_CHECK_NOTNULL(val)
196 #endif // NDEBUG
197
198 // ---------------------- Support for std objects --------------------------
199 // These are adapted from glog to support a limited set of logging capability
200 // for STL objects.
201
202 namespace std {
203 // Forward declare these two, and define them after all the container streams
204 // operators so that we can recurse from pair -> container -> container -> pair
205 // properly.
206 template <class First, class Second>
207 std::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p);
208 } // namespace std
209
210 namespace c10 {
211 template <class Iter>
212 void PrintSequence(std::ostream& ss, Iter begin, Iter end);
213 } // namespace c10
214
215 namespace std {
216 #define INSTANTIATE_FOR_CONTAINER(container) \
217 template <class... Types> \
218 std::ostream& operator<<( \
219 std::ostream& out, const container<Types...>& seq) { \
220 c10::PrintSequence(out, seq.begin(), seq.end()); \
221 return out; \
222 }
223
224 INSTANTIATE_FOR_CONTAINER(std::vector)
225 INSTANTIATE_FOR_CONTAINER(std::map)
226 INSTANTIATE_FOR_CONTAINER(std::set)
227 #undef INSTANTIATE_FOR_CONTAINER
228
229 template <class First, class Second>
230 inline std::ostream& operator<<(
231 std::ostream& out,
232 const std::pair<First, Second>& p) {
233 out << '(' << p.first << ", " << p.second << ')';
234 return out;
235 }
236
237 inline std::ostream& operator<<(std::ostream& out, const std::nullptr_t&) {
238 out << "(null)";
239 return out;
240 }
241 } // namespace std
242
243 namespace c10 {
244 template <class Iter>
PrintSequence(std::ostream & out,Iter begin,Iter end)245 inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
246 // Output at most 100 elements -- appropriate if used for logging.
247 for (int i = 0; begin != end && i < 100; ++i, ++begin) {
248 if (i > 0)
249 out << ' ';
250 out << *begin;
251 }
252 if (begin != end) {
253 out << " ...";
254 }
255 }
256 } // namespace c10
257
258 #endif // C10_UTIL_LOGGING_IS_NOT_GOOGLE_GLOG_H_
259