1 | #ifndef C10_UTIL_LOGGING_H_ |
2 | #define C10_UTIL_LOGGING_H_ |
3 | |
4 | #include <climits> |
5 | #include <exception> |
6 | #include <functional> |
7 | #include <limits> |
8 | #include <sstream> |
9 | |
10 | #include <c10/macros/Macros.h> |
11 | #include <c10/util/Exception.h> |
12 | #include <c10/util/Flags.h> |
13 | #include <c10/util/StringUtil.h> |
14 | |
15 | // CAFFE2_LOG_THRESHOLD is a compile time flag that would allow us to turn off |
16 | // logging at compile time so no logging message below that level is produced |
17 | // at all. The value should be between INT_MIN and CAFFE_FATAL. |
18 | #ifndef CAFFE2_LOG_THRESHOLD |
19 | // If we have not defined the compile time log threshold, we keep all the |
20 | // log cases. |
21 | #define CAFFE2_LOG_THRESHOLD INT_MIN |
22 | #endif // CAFFE2_LOG_THRESHOLD |
23 | |
24 | // Below are different implementations for glog and non-glog cases. |
25 | #ifdef C10_USE_GLOG |
26 | #include <c10/util/logging_is_google_glog.h> |
27 | #else // !C10_USE_GLOG |
28 | #include <c10/util/logging_is_not_google_glog.h> |
29 | #endif // C10_USE_GLOG |
30 | |
31 | C10_DECLARE_int(caffe2_log_level); |
32 | C10_DECLARE_bool(caffe2_use_fatal_for_enforce); |
33 | |
34 | // Some versions of GLOG support less-spammy version of LOG_EVERY_MS. If it's |
35 | // not available - just short-circuit to the always working one one. |
36 | // We define the C10_ name to avoid confusing other files |
37 | #ifdef LOG_EVERY_MS |
38 | #define C10_LOG_EVERY_MS(severity, ms) LOG_EVERY_MS(severity, ms) |
39 | #else |
40 | #define C10_LOG_EVERY_MS(severity, ms) LOG(severity) |
41 | #endif |
42 | |
43 | // Same for LOG_FIRST_N |
44 | #ifdef LOG_FIRST_N |
45 | #define C10_LOG_FIRST_N(severity, n) LOG_FIRST_N(severity, n) |
46 | #else |
47 | #define C10_LOG_FIRST_N(severity, n) LOG(severity) |
48 | #endif |
49 | |
50 | // Same for LOG_EVERY_N |
51 | #ifdef LOG_EVERY_N |
52 | #define C10_LOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n) |
53 | #else |
54 | #define C10_LOG_EVERY_N(severity, n) LOG(severity) |
55 | #endif |
56 | |
57 | namespace c10 { |
58 | |
59 | using std::string; |
60 | |
61 | // Functions that we use for initialization. |
62 | C10_API bool InitCaffeLogging(int* argc, char** argv); |
63 | C10_API void UpdateLoggingLevelsFromFlags(); |
64 | |
65 | [[noreturn]] C10_API void ThrowEnforceNotMet( |
66 | const char* file, |
67 | const int line, |
68 | const char* condition, |
69 | const std::string& msg, |
70 | const void* caller = nullptr); |
71 | |
72 | [[noreturn]] C10_API void ThrowEnforceNotMet( |
73 | const char* file, |
74 | const int line, |
75 | const char* condition, |
76 | const char* msg, |
77 | const void* caller = nullptr); |
78 | |
79 | [[noreturn]] C10_API inline void ThrowEnforceNotMet( |
80 | const char* file, |
81 | const int line, |
82 | const char* condition, |
83 | detail::CompileTimeEmptyString /*msg*/, |
84 | const void* caller = nullptr) { |
85 | ThrowEnforceNotMet(file, line, condition, "" , caller); |
86 | } |
87 | |
88 | [[noreturn]] C10_API void ThrowEnforceFiniteNotMet( |
89 | const char* file, |
90 | const int line, |
91 | const char* condition, |
92 | const std::string& msg, |
93 | const void* caller = nullptr); |
94 | |
95 | [[noreturn]] C10_API void ThrowEnforceFiniteNotMet( |
96 | const char* file, |
97 | const int line, |
98 | const char* condition, |
99 | const char* msg, |
100 | const void* caller = nullptr); |
101 | |
102 | [[noreturn]] C10_API inline void ThrowEnforceFiniteNotMet( |
103 | const char* file, |
104 | const int line, |
105 | const char* condition, |
106 | detail::CompileTimeEmptyString /*msg*/, |
107 | const void* caller = nullptr) { |
108 | ThrowEnforceFiniteNotMet(file, line, condition, "" , caller); |
109 | } |
110 | |
111 | constexpr bool IsUsingGoogleLogging() { |
112 | #ifdef C10_USE_GLOG |
113 | return true; |
114 | #else |
115 | return false; |
116 | #endif |
117 | } |
118 | |
119 | /** |
120 | * A utility to allow one to show log info to stderr after the program starts. |
121 | * |
122 | * This is similar to calling GLOG's --logtostderr, or setting caffe2_log_level |
123 | * to smaller than INFO. You are recommended to only use this in a few sparse |
124 | * cases, such as when you want to write a tutorial or something. Normally, use |
125 | * the commandline flags to set the log level. |
126 | */ |
127 | C10_API void ShowLogInfoToStderr(); |
128 | |
129 | C10_API void SetStackTraceFetcher(std::function<string(void)> fetcher); |
130 | |
131 | using EnforceNotMet = ::c10::Error; |
132 | |
133 | #define CAFFE_ENFORCE(condition, ...) \ |
134 | do { \ |
135 | if (C10_UNLIKELY(!(condition))) { \ |
136 | ::c10::ThrowEnforceNotMet( \ |
137 | __FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__)); \ |
138 | } \ |
139 | } while (false) |
140 | |
141 | #define CAFFE_ENFORCE_FINITE(condition, ...) \ |
142 | do { \ |
143 | if (C10_UNLIKELY(!(condition))) { \ |
144 | ::c10::ThrowEnforceFiniteNotMet( \ |
145 | __FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__)); \ |
146 | } \ |
147 | } while (false) |
148 | |
149 | #define CAFFE_ENFORCE_WITH_CALLER(condition, ...) \ |
150 | do { \ |
151 | if (C10_UNLIKELY(!(condition))) { \ |
152 | ::c10::ThrowEnforceNotMet( \ |
153 | __FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__), this); \ |
154 | } \ |
155 | } while (false) |
156 | |
157 | #define CAFFE_THROW(...) \ |
158 | ::c10::ThrowEnforceNotMet(__FILE__, __LINE__, "", ::c10::str(__VA_ARGS__)) |
159 | |
160 | /** |
161 | * Rich logging messages |
162 | * |
163 | * CAFFE_ENFORCE_THAT can be used with one of the "checker functions" that |
164 | * capture input argument values and add it to the exception message. E.g. |
165 | * `CAFFE_ENFORCE_THAT(Equals(foo(x), bar(y)), "Optional additional message")` |
166 | * would evaluate both foo and bar only once and if the results are not equal - |
167 | * include them in the exception message. |
168 | * |
169 | * Some of the basic checker functions like Equals or Greater are already |
170 | * defined below. Other header might define customized checkers by adding |
171 | * functions to caffe2::enforce_detail namespace. For example: |
172 | * |
173 | * namespace caffe2 { namespace enforce_detail { |
174 | * inline EnforceFailMessage IsVector(const vector<int64_t>& shape) { |
175 | * if (shape.size() == 1) { return EnforceOK(); } |
176 | * return c10::str("Shape ", shape, " is not a vector"); |
177 | * } |
178 | * }} |
179 | * |
180 | * With further usages like `CAFFE_ENFORCE_THAT(IsVector(Input(0).dims()))` |
181 | * |
182 | * Convenient wrappers for binary operations like CAFFE_ENFORCE_EQ are provided |
183 | * too. Please use them instead of TORCH_CHECK_EQ and friends for failures in |
184 | * user-provided input. |
185 | */ |
186 | |
187 | namespace enforce_detail { |
188 | |
189 | template <typename T1, typename T2> |
190 | std::string enforceFailMsgImpl(const T1& x, const T2& y) { |
191 | return c10::str(x, " vs " , y); |
192 | } |
193 | |
194 | template <typename T1, typename T2, typename... Args> |
195 | std::string enforceFailMsgImpl(const T1& x, const T2& y, const Args&... args) { |
196 | return c10::str(x, " vs " , y, ". " , args...); |
197 | } |
198 | |
199 | template <typename Pred, typename T1, typename T2, typename... Args> |
200 | void enforceThatImpl( |
201 | Pred p, |
202 | const T1& lhs, |
203 | const T2& rhs, |
204 | const char* file, |
205 | int line, |
206 | const char* expr, |
207 | const void* caller, |
208 | const Args&... args) { |
209 | if (C10_UNLIKELY(!(p(lhs, rhs)))) { |
210 | ::c10::ThrowEnforceNotMet( |
211 | file, |
212 | line, |
213 | expr, |
214 | ::c10::enforce_detail::enforceFailMsgImpl(lhs, rhs, args...), |
215 | caller); |
216 | } |
217 | } |
218 | #define CAFFE_ENFORCE_THAT_IMPL(op, lhs, rhs, expr, ...) \ |
219 | ::c10::enforce_detail::enforceThatImpl( \ |
220 | op, lhs, rhs, __FILE__, __LINE__, expr, nullptr, ##__VA_ARGS__) |
221 | |
222 | #define CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER(op, lhs, rhs, expr, ...) \ |
223 | ::c10::enforce_detail::enforceThatImpl( \ |
224 | op, (lhs), (rhs), __FILE__, __LINE__, expr, this, ##__VA_ARGS__) |
225 | |
226 | } // namespace enforce_detail |
227 | |
228 | #define CAFFE_ENFORCE_THAT(cmp, op, lhs, rhs, ...) \ |
229 | CAFFE_ENFORCE_THAT_IMPL(cmp, lhs, rhs, #lhs " " #op " " #rhs, ##__VA_ARGS__) |
230 | |
231 | #define CAFFE_ENFORCE_BINARY_OP(cmp, op, x, y, ...) \ |
232 | CAFFE_ENFORCE_THAT_IMPL(cmp, x, y, #x " " #op " " #y, ##__VA_ARGS__) |
233 | #define CAFFE_ENFORCE_EQ(x, y, ...) \ |
234 | CAFFE_ENFORCE_BINARY_OP(std::equal_to<void>(), ==, x, y, ##__VA_ARGS__) |
235 | #define CAFFE_ENFORCE_NE(x, y, ...) \ |
236 | CAFFE_ENFORCE_BINARY_OP(std::not_equal_to<void>(), !=, x, y, ##__VA_ARGS__) |
237 | #define CAFFE_ENFORCE_LE(x, y, ...) \ |
238 | CAFFE_ENFORCE_BINARY_OP(std::less_equal<void>(), <=, x, y, ##__VA_ARGS__) |
239 | #define CAFFE_ENFORCE_LT(x, y, ...) \ |
240 | CAFFE_ENFORCE_BINARY_OP(std::less<void>(), <, x, y, ##__VA_ARGS__) |
241 | #define CAFFE_ENFORCE_GE(x, y, ...) \ |
242 | CAFFE_ENFORCE_BINARY_OP(std::greater_equal<void>(), >=, x, y, ##__VA_ARGS__) |
243 | #define CAFFE_ENFORCE_GT(x, y, ...) \ |
244 | CAFFE_ENFORCE_BINARY_OP(std::greater<void>(), >, x, y, ##__VA_ARGS__) |
245 | |
246 | #define CAFFE_ENFORCE_BINARY_OP_WITH_CALLER(cmp, op, x, y, ...) \ |
247 | CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER( \ |
248 | cmp, x, y, #x " " #op " " #y, ##__VA_ARGS__) |
249 | #define CAFFE_ENFORCE_EQ_WITH_CALLER(x, y, ...) \ |
250 | CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \ |
251 | std::equal_to<void>(), ==, x, y, ##__VA_ARGS__) |
252 | #define CAFFE_ENFORCE_NE_WITH_CALLER(x, y, ...) \ |
253 | CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \ |
254 | std::not_equal_to<void>(), !=, x, y, ##__VA_ARGS__) |
255 | #define CAFFE_ENFORCE_LE_WITH_CALLER(x, y, ...) \ |
256 | CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \ |
257 | std::less_equal<void>(), <=, x, y, ##__VA_ARGS__) |
258 | #define CAFFE_ENFORCE_LT_WITH_CALLER(x, y, ...) \ |
259 | CAFFE_ENFORCE_BINARY_OP_WITH_CALLER(std::less<void>(), <, x, y, ##__VA_ARGS__) |
260 | #define CAFFE_ENFORCE_GE_WITH_CALLER(x, y, ...) \ |
261 | CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \ |
262 | std::greater_equal<void>(), >=, x, y, ##__VA_ARGS__) |
263 | #define CAFFE_ENFORCE_GT_WITH_CALLER(x, y, ...) \ |
264 | CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \ |
265 | std::greater<void>(), >, x, y, ##__VA_ARGS__) |
266 | |
267 | /** |
268 | * Very lightweight logging for the first time API usage. It's beneficial for |
269 | * tracking of individual functionality usage in larger applications. |
270 | * |
271 | * In order to ensure light-weightedness of logging, we utilize static variable |
272 | * trick - LogAPIUsage will be invoked only once and further invocations will |
273 | * just do an atomic check. |
274 | * |
275 | * Example: |
276 | * // Logs caller info with an arbitrary text event, if there is a usage. |
277 | * C10_LOG_API_USAGE_ONCE("my_api"); |
278 | */ |
279 | #define C10_LOG_API_USAGE_ONCE(...) \ |
280 | C10_UNUSED static bool C10_ANONYMOUS_VARIABLE(logFlag) = \ |
281 | ::c10::detail::LogAPIUsageFakeReturn(__VA_ARGS__); |
282 | |
283 | // API usage logging capabilities |
284 | C10_API void SetAPIUsageLogger(std::function<void(const std::string&)> logger); |
285 | C10_API void LogAPIUsage(const std::string& context); |
286 | |
287 | // PyTorch ddp usage logging capabilities |
288 | // DDPLoggingData holds data that can be logged in applications |
289 | // for analysis and debugging. Data structure is defined in |
290 | // c10 directory so that it can be easily imported by both c10 |
291 | // and torch files. |
292 | struct DDPLoggingData { |
293 | // logging fields that are string types. |
294 | std::map<std::string, std::string> strs_map; |
295 | // logging fields that are int64_t types. |
296 | std::map<std::string, int64_t> ints_map; |
297 | }; |
298 | |
299 | C10_API void SetPyTorchDDPUsageLogger( |
300 | std::function<void(const DDPLoggingData&)> logger); |
301 | C10_API void LogPyTorchDDPUsage(const DDPLoggingData& ddpData); |
302 | |
303 | namespace detail { |
304 | // Return value is needed to do the static variable initialization trick |
305 | C10_API bool LogAPIUsageFakeReturn(const std::string& context); |
306 | } // namespace detail |
307 | |
308 | // Initializes the c10 logger. |
309 | C10_API void initLogging(); |
310 | |
311 | } // namespace c10 |
312 | |
313 | #endif // C10_UTIL_LOGGING_H_ |
314 | |