forked from pytorch/pytorch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathException.h
393 lines (340 loc) · 15.8 KB
/
Exception.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
#ifndef C10_UTIL_EXCEPTION_H_
#define C10_UTIL_EXCEPTION_H_
#include "c10/macros/Macros.h"
#include "c10/util/StringUtil.h"
#include "c10/util/Deprecated.h"
#include <cstddef>
#include <exception>
#include <ostream>
#include <sstream>
#include <string>
#include <vector>
#if defined(_MSC_VER) && _MSC_VER <= 1900
#define __func__ __FUNCTION__
#endif
namespace c10 {
/// The primary ATen error class.
/// Provides a complete error message with source location information via
/// `what()`, and a more concise message via `what_without_backtrace()`.
/// Don't throw this directly; use TORCH_CHECK/TORCH_INTERNAL_ASSERT instead.
///
/// NB: c10::Error is handled specially by the default torch to suppress the
/// backtrace, see torch/csrc/Exceptions.h
class C10_API Error : public std::exception {
std::vector<std::string> msg_stack_;
std::string backtrace_;
// These two are derived fields from msg_stack_ and backtrace_, but we need
// fields for the strings so that we can return a const char* (as the
// signature of std::exception requires).
std::string msg_;
std::string msg_without_backtrace_;
// This is a little debugging trick: you can stash a relevant pointer
// in caller, and then when you catch the exception, you can compare
// against pointers you have on hand to get more information about
// where the exception came from. In Caffe2, this is used to figure
// out which operator raised an exception.
const void* caller_;
public:
Error(
const std::string& msg,
const std::string& backtrace,
const void* caller = nullptr);
Error(SourceLocation source_location, const std::string& msg);
Error(
const char* file,
const uint32_t line,
const char* condition,
const std::string& msg,
const std::string& backtrace,
const void* caller = nullptr);
void AppendMessage(const std::string& msg);
// Compute the full message from msg_ and msg_without_backtrace_
// TODO: Maybe this should be private
std::string msg() const;
std::string msg_without_backtrace() const;
const std::vector<std::string>& msg_stack() const {
return msg_stack_;
}
/// Returns the complete error message, including the source location.
const char* what() const noexcept override {
return msg_.c_str();
}
const void* caller() const noexcept {
return caller_;
}
/// Returns only the error message string, without source location.
const char* what_without_backtrace() const noexcept {
return msg_without_backtrace_.c_str();
}
};
class C10_API Warning {
using handler_t =
void (*)(const SourceLocation& source_location, const char* msg);
public:
/// Issue a warning with a given message. Dispatched to the current
/// warning handler.
static void warn(SourceLocation source_location, std::string msg);
/// Sets the global warning handler. This is not thread-safe, so it should
/// generally be called once during initialization.
static void set_warning_handler(handler_t handler);
/// The default warning handler. Prints the message to stderr.
static void print_warning(
const SourceLocation& source_location,
const char* msg);
private:
static handler_t warning_handler_;
};
// Used in ATen for out-of-bound indices that can reasonably only be detected
// lazily inside a kernel (See: advanced indexing). These turn into
// IndexError when they cross to Python.
class C10_API IndexError : public Error {
using Error::Error;
};
// A utility function to return an exception std::string by prepending its
// exception type before its what() content
C10_API std::string GetExceptionString(const std::exception& e);
namespace detail {
// Return x if it is non-empty; otherwise return y.
inline std::string if_empty_then(std::string x, std::string y) {
if (x.empty()) {
return y;
} else {
return x;
}
}
}
} // namespace c10
// Private helper macro for implementing TORCH_INTERNAL_ASSERT and TORCH_CHECK
//
// Note: In the debug build With MSVC, __LINE__ might be of long type (a.k.a int32_t),
// which is different from the definition of `SourceLocation` that requires
// unsigned int (a.k.a uint32_t) and may cause a compile error with the message:
// error C2397: conversion from 'long' to 'uint32_t' requires a narrowing conversion
// Here the static cast is used to pass the build.
#define C10_THROW_ERROR(err_type, msg) \
throw ::c10::err_type({__func__, __FILE__, static_cast<uint32_t>(__LINE__)}, msg)
// Private helper macro for workaround MSVC misexpansion of nested macro
// invocations involving __VA_ARGS__. See
// https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
#define C10_EXPAND_MSVC_WORKAROUND(x) x
// On nvcc, C10_UNLIKELY thwarts missing return statement analysis. In cases
// where the unlikely expression may be a constant, use this macro to ensure
// return statement analysis keeps working (at the cost of not getting the
// likely/unlikely annotation on nvcc). https://github.com/pytorch/pytorch/issues/21418
//
// Currently, this is only used in the error reporting macros below. If you
// want to use it more generally, move me to Macros.h
//
// TODO: Brian Vaughan observed that we might be able to get this to work on nvcc
// by writing some sort of C++ overload that distinguishes constexpr inputs
// from non-constexpr. Since there isn't any evidence that losing C10_UNLIKELY
// in nvcc is causing us perf problems, this is not yet implemented, but this
// might be an interesting piece of C++ code for an intrepid bootcamper to
// write.
#if defined(__CUDACC__)
#define C10_UNLIKELY_OR_CONST(e) e
#else
#define C10_UNLIKELY_OR_CONST(e) C10_UNLIKELY(e)
#endif
// ----------------------------------------------------------------------------
// Error reporting macros
// ----------------------------------------------------------------------------
// A utility macro to provide assert()-like functionality; that is, enforcement
// of internal invariants in code. It supports an arbitrary number of extra
// arguments (evaluated only on failure), which will be printed in the assert
// failure message using operator<< (this is useful to print some variables
// which may be useful for debugging.)
//
// Usage:
// TORCH_INTERNAL_ASSERT(should_be_true);
// TORCH_INTERNAL_ASSERT(x == 0, "x = ", x);
//
// Assuming no bugs in PyTorch, the conditions tested by this macro should
// always be true; e.g., it should be possible to disable all of these
// conditions without changing observable user behavior. If you would like to
// do error reporting for user input, please use TORCH_CHECK instead.
//
// NOTE: It is SAFE to use this macro in production code; on failure, this
// simply raises an exception, it does NOT unceremoniously quit the process
// (unlike assert()).
//
#ifdef C10_MOBILE
#define TORCH_INTERNAL_ASSERT(cond, ...) \
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
C10_THROW_ERROR(Error, \
#cond " INTERNAL ASSERT FAILED at" \
__FILE__ \
); \
}
#else
#define TORCH_INTERNAL_ASSERT(cond, ...) \
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
C10_THROW_ERROR(Error, ::c10::str( \
#cond " INTERNAL ASSERT FAILED at ", \
__FILE__, \
":", \
__LINE__, \
", please report a bug to PyTorch. ", \
::c10::str(__VA_ARGS__) \
)); \
}
#endif
// A utility macro to make it easier to test for error conditions from user
// input. Like TORCH_INTERNAL_ASSERT, it supports an arbitrary number of extra
// arguments (evaluated only on failure), which will be printed in the error
// message using operator<< (e.g., you can pass any object which has
// operator<< defined. Most objects in PyTorch have these definitions!)
//
// Usage:
// TORCH_CHECK(should_be_true); // A default error message will be provided
// // in this case; but we recommend writing an
// // explicit error message, as it is more
// // user friendly.
// TORCH_CHECK(x == 0, "Expected x to be 0, but got ", x);
//
// On failure, this macro will raise an exception. If this exception propagates
// to Python, it will convert into a Python RuntimeError.
//
// NOTE: It is SAFE to use this macro in production code; on failure, this
// simply raises an exception, it does NOT unceremoniously quit the process
// (unlike CHECK() from glog.)
//
#ifdef C10_MOBILE
#define TORCH_CHECK(cond, ...) \
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
C10_THROW_ERROR(Error, \
#cond " CHECK FAILED at " \
__FILE__ \
); \
}
#else
#define TORCH_CHECK(cond, ...) \
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
C10_THROW_ERROR(Error, \
::c10::detail::if_empty_then( \
::c10::str(__VA_ARGS__), \
"Expected " #cond " to be true, but got false. " \
"(Could this error message be improved? If so, " \
"please report an enhancement request to PyTorch.)" \
) \
); \
}
#endif
// TODO: We're going to get a lot of similar looking string literals
// this way; check if this actually affects binary size.
// Like TORCH_CHECK, but raises IndexErrors instead of Errors.
#ifdef C10_MOBILE
#define TORCH_CHECK_INDEX(cond, ...) \
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
C10_THROW_ERROR(Error, \
#cond " INDEX CHECK FAILED at " \
__FILE__ \
); \
}
#else
#define TORCH_CHECK_INDEX(cond, ...) \
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
C10_THROW_ERROR(IndexError, \
::c10::detail::if_empty_then( \
::c10::str(__VA_ARGS__), \
"Expected " #cond " to be true, but got false. " \
"(Could this error message be improved? If so, " \
"please report an enhancement request to PyTorch.)" \
) \
); \
}
#endif
// Report a warning to the user. Accepts an arbitrary number of extra
// arguments which are concatenated into the warning message using operator<<
//
#define TORCH_WARN(...) \
::c10::Warning::warn({__func__, __FILE__, static_cast<uint32_t>(__LINE__)}, ::c10::str(__VA_ARGS__))
// ----------------------------------------------------------------------------
// Deprecated macros
// ----------------------------------------------------------------------------
namespace c10 { namespace detail {
/*
// Deprecation disabled until we fix sites in our codebase
C10_DEPRECATED_MESSAGE("AT_ERROR(msg) is deprecated, use TORCH_CHECK(false, msg) instead.")
*/
inline void deprecated_AT_ERROR() {}
/*
// Deprecation disabled until we fix sites in our codebase
C10_DEPRECATED_MESSAGE("AT_INDEX_ERROR(msg) is deprecated, use TORCH_CHECK_INDEX(false, msg) instead.")
*/
inline void deprecated_AT_INDEX_ERROR() {}
/*
// Deprecation disabled until we fix sites in our codebase
C10_DEPRECATED_MESSAGE("AT_WARN is deprecated, use TORCH_WARN instead.")
*/
inline void deprecated_AT_WARN() {}
C10_DEPRECATED_MESSAGE("AT_CHECK is deprecated, use TORCH_CHECK instead.")
inline void deprecated_AT_CHECK() {}
/*
// Deprecation disabled until we fix sites in our codebase
C10_DEPRECATED_MESSAGE("AT_ASSERT is deprecated, if you mean to indicate an internal invariant failure, use " \
"TORCH_INTERNAL_ASSERT instead; if you mean to do user error checking, use " \
"TORCH_CHECK. See https://github.com/pytorch/pytorch/issues/20287 for more details.")
*/
inline void deprecated_AT_ASSERT() {}
/*
// Deprecation disabled until we fix sites in our codebase
C10_DEPRECATED_MESSAGE("AT_ASSERTM is deprecated, if you mean to indicate an internal invariant failure, use " \
"TORCH_INTERNAL_ASSERT instead; if you mean to do user error checking, use " \
"TORCH_CHECK. See https://github.com/pytorch/pytorch/issues/20287 for more details.")
*/
inline void deprecated_AT_ASSERTM() {}
}} // namespace c10::detail
// Deprecated alias; this alias was deprecated because it wasn't clear to
// people that you should use a macro with AT_ prefix inside the torch/csrc
// directory. Use TORCH_CHECK instead.
#define AT_CHECK(...) \
do { \
::c10::detail::deprecated_AT_CHECK(); \
C10_EXPAND_MSVC_WORKAROUND(TORCH_CHECK(__VA_ARGS__)); \
} while (false)
// Deprecated alias; this alias was deprecated because people kept mistakenly
// using it for user error checking. Use TORCH_INTERNAL_ASSERT or TORCH_CHECK
// instead. See https://github.com/pytorch/pytorch/issues/20287 for more details.
#define AT_ASSERT(...) \
do { \
::c10::detail::deprecated_AT_ASSERT(); \
C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(__VA_ARGS__)); \
} while (false)
// Deprecated alias, like AT_ASSERT. The new TORCH_INTERNAL_ASSERT macro supports
// both 0-ary and variadic calls, so having a separate message-accepting macro
// is not necessary.
//
// NB: we MUST include cond explicitly here, as MSVC will miscompile the macro
// expansion, shunting all of __VA_ARGS__ to cond. An alternate workaround
// can be seen at
// https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
#define AT_ASSERTM(cond, ...) \
do { \
::c10::detail::deprecated_AT_ASSERTM(); \
C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(cond, __VA_ARGS__)); \
} while (false)
// Deprecated alias; this alias was deprecated because it represents extra API
// surface that makes it hard for people to understand what macro to use.
// Use TORCH_CHECK(false, ...) or TORCH_INTERNAL_ASSERT(false, ...) to
// unconditionally fail at a line of code.
#define AT_ERROR(...) \
do { \
::c10::detail::deprecated_AT_ERROR(); \
C10_EXPAND_MSVC_WORKAROUND(TORCH_CHECK(false, ::c10::str(__VA_ARGS__))); \
} while (false)
// Deprecated alias; this alias was deprecated for consistency with TORCH_CHECK.
#define AT_INDEX_ERROR(...) \
do { \
::c10::detail::deprecated_AT_INDEX_ERROR(); \
C10_EXPAND_MSVC_WORKAROUND(TORCH_CHECK_INDEX(false, ::c10::str(__VA_ARGS__))); \
} while (false)
// Deprecated alias; this alias was deprecated because it wasn't clear to
// people that you should use a macro with AT_ prefix inside the torch/csrc
// directory. Use TORCH_WARN instead.
#define AT_WARN(...) \
do { \
::c10::detail::deprecated_AT_WARN(); \
C10_EXPAND_MSVC_WORKAROUND(TORCH_WARN(__VA_ARGS__)); \
} while (false)
#endif // C10_UTIL_EXCEPTION_H_