|
| 1 | +.. _error_guide: |
| 2 | + |
| 3 | +Error Handling Guide |
| 4 | +==================== |
| 5 | +TVM contains structured error classes to indicate specific types of error. |
| 6 | +Please raise a specific error type when possible, so that users can |
| 7 | +write code to handle a specific error category if necessary. |
| 8 | + |
| 9 | +All the error types are defined in :any:`tvm.error` namespace. |
| 10 | +You can directly raise the specific error object in python. |
| 11 | +In other languages like c++, you simply add ``<ErrorType>:`` prefix to |
| 12 | +the error message(see below). |
| 13 | + |
| 14 | +Raise a Specific Error in C++ |
| 15 | +----------------------------- |
| 16 | +You can add ``<ErrorType>:`` prefix to your error message to |
| 17 | +raise an error of the corresponding type. |
| 18 | +Note that you do not have to add a new type |
| 19 | +:any:`tvm.error.TVMError` will be raised by default when |
| 20 | +there is no error type prefix in the message. |
| 21 | +This mechanism works for both ``LOG(FATAL)`` and ``CHECK`` macros. |
| 22 | +The following code gives an example on how to do so. |
| 23 | + |
| 24 | +.. code:: c |
| 25 | +
|
| 26 | + // src/api_test.cc |
| 27 | + void ErrorTest(int x, int y) { |
| 28 | + CHECK_EQ(x, y) << "ValueError: expect x and y to be equal." |
| 29 | + if (x == 1) { |
| 30 | + LOG(FATAL) << "InternalError: cannot reach here"; |
| 31 | + } |
| 32 | + } |
| 33 | +
|
| 34 | +The above function is registered as PackedFunc into the python frontend, |
| 35 | +under the name ``tvm._api_internal._ErrorTest``. |
| 36 | +Here is what will happen if we call the registered function: |
| 37 | + |
| 38 | +.. code:: |
| 39 | +
|
| 40 | + >>> import tvm |
| 41 | + >>> tvm._api_internal._ErrorTest(0, 1) |
| 42 | + Traceback (most recent call last): |
| 43 | + File "<stdin>", line 1, in <module> |
| 44 | + File "/path/to/tvm/python/tvm/_ffi/_ctypes/function.py", line 190, in __call__ |
| 45 | + raise get_last_ffi_error() |
| 46 | + ValueError: Traceback (most recent call last): |
| 47 | + [bt] (3) /path/to/tvm/build/libtvm.so(TVMFuncCall+0x48) [0x7fab500b8ca8] |
| 48 | + [bt] (2) /path/to/tvm/build/libtvm.so(+0x1c4126) [0x7fab4f7f5126] |
| 49 | + [bt] (1) /path/to/tvm/build/libtvm.so(+0x1ba2f8) [0x7fab4f7eb2f8] |
| 50 | + [bt] (0) /path/to/tvm/build/libtvm.so(+0x177d12) [0x7fab4f7a8d12] |
| 51 | + File "/path/to/tvm/src/api/api_test.cc", line 80 |
| 52 | + ValueError: Check failed: x == y (0 vs. 1) : expect x and y to be equal. |
| 53 | + >>> |
| 54 | + >>> tvm._api_internal._ErrorTest(1, 1) |
| 55 | + Traceback (most recent call last): |
| 56 | + File "<stdin>", line 1, in <module> |
| 57 | + File "/path/to/tvm/python/tvm/_ffi/_ctypes/function.py", line 190, in __call__ |
| 58 | + raise get_last_ffi_error() |
| 59 | + tvm.error.InternalError: Traceback (most recent call last): |
| 60 | + [bt] (3) /path/to/tvm/build/libtvm.so(TVMFuncCall+0x48) [0x7fab500b8ca8] |
| 61 | + [bt] (2) /path/to/tvm/build/libtvm.so(+0x1c4126) [0x7fab4f7f5126] |
| 62 | + [bt] (1) /path/to/tvm/build/libtvm.so(+0x1ba35c) [0x7fab4f7eb35c] |
| 63 | + [bt] (0) /path/to/tvm/build/libtvm.so(+0x177d12) [0x7fab4f7a8d12] |
| 64 | + File "/path/to/tvm/src/api/api_test.cc", line 83 |
| 65 | + InternalError: cannot reach here |
| 66 | + TVM hint: You hit an internal error. Please open a thread on https://discuss.tvm.ai/ to report it. |
| 67 | +
|
| 68 | +As you can see in the above example, TVM's ffi system combines |
| 69 | +both the python and c++'s stacktrace into a single message, and generate the |
| 70 | +corresponding error class automatically. |
| 71 | + |
| 72 | + |
| 73 | +How to choose an Error Type |
| 74 | +--------------------------- |
| 75 | +You can go through the error types are listed below, try to use common |
| 76 | +sense and also refer to the choices in the existing code. |
| 77 | +We try to keep a reasonable amount of error types. |
| 78 | +If you feel there is a need to add a new error type, do the following steps: |
| 79 | + |
| 80 | +- Send a RFC proposal with a description and usage examples in the current codebase. |
| 81 | +- Add the new error type to :any:`tvm.error` with clear documents. |
| 82 | +- Update the list in this file to include the new error type. |
| 83 | +- Change the code to use the new error type. |
| 84 | + |
| 85 | +We also recommend to use less abstraction when creating the short error messages. |
| 86 | +The code is more readable in this way, and also opens path to craft specific |
| 87 | +error messages when necessary. |
| 88 | + |
| 89 | +.. code:: python |
| 90 | +
|
| 91 | + def preferred(): |
| 92 | + # Very clear about what is being raised and what is the error message. |
| 93 | + raise OpNotImplemented("Operator relu is not implemented in the MXNet fronend") |
| 94 | +
|
| 95 | + def _op_not_implemented(op_name): |
| 96 | + return OpNotImplemented("Operator {} is not implemented.").format(op_name) |
| 97 | +
|
| 98 | + def not_preferred(): |
| 99 | + # Introduces another level of indirection. |
| 100 | + raise _op_not_implemented("relu") |
| 101 | +
|
| 102 | +If we need to introduce a wrapper function that constructs multi-line error messages, |
| 103 | +please put wrapper in the same file so other developers can look up the implementation easily. |
| 104 | + |
| 105 | + |
| 106 | +System-wide Errors |
| 107 | +------------------ |
| 108 | + |
| 109 | +.. autoclass:: tvm.error.TVMError |
| 110 | + |
| 111 | +.. autoclass:: tvm.error.InternalError |
| 112 | + |
| 113 | + |
| 114 | +Frontend Errors |
| 115 | +--------------- |
| 116 | +.. autoclass:: tvm.error.OpNotImplemented |
| 117 | + |
| 118 | +.. autoclass:: tvm.error.OpAttributeInvalid |
| 119 | + |
| 120 | +.. autoclass:: tvm.error.OpAttributeRequired |
| 121 | + |
| 122 | +.. autoclass:: tvm.error.OpAttributeNotImplemented |
0 commit comments