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