错误处理指南
TVM 包含结构化的错误类,用于指示特定类型的错误。请尽可能引发特定错误类型,以便用户可以编写代码来处理必要的特定错误类别。您可以直接在 Python 中引发特定的错误对象。在其他语言(如 C++)中,您只需在错误消息中添加 <ErrorType>:
前缀(见下文)。
注意
请参考 tvm.error
以获取错误列表。
在 C++ 中引发特定错误
您可以将 <ErrorType>:
前缀添加到您的错误消息中,以引发相应类型的错误。请注意,您不必添加新类型,如果没有在消息中添加错误类型前缀,则默认会引发 tvm.error.TVMError
。此机制适用于 LOG(FATAL)
和 ICHECK
宏。以下代码给出了如何执行此操作的示例。
// src/api_test.cc
void ErrorTest(int x, int y) {
ICHECK_EQ(x, y) << "ValueError: expect x and y to be equal."
if (x == 1) {
LOG(FATAL) << "InternalError: cannot reach here";
}
}
上面的函数作为 PackedFunc 注册到 Python 前端,名称为 tvm._api_internal._ErrorTest
。以下是如果我们调用注册函数会发生的情况
>>> import tvm
>>> tvm.testing.ErrorTest(0, 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/path/to/tvm/python/tvm/_ffi/_ctypes/function.py", line 190, in __call__
raise get_last_ffi_error()
ValueError: Traceback (most recent call last):
[bt] (3) /path/to/tvm/build/libtvm.so(TVMFuncCall+0x48) [0x7fab500b8ca8]
[bt] (2) /path/to/tvm/build/libtvm.so(+0x1c4126) [0x7fab4f7f5126]
[bt] (1) /path/to/tvm/build/libtvm.so(+0x1ba2f8) [0x7fab4f7eb2f8]
[bt] (0) /path/to/tvm/build/libtvm.so(+0x177d12) [0x7fab4f7a8d12]
File "/path/to/tvm/src/api/api_test.cc", line 80
ValueError: Check failed: x == y (0 vs. 1) : expect x and y to be equal.
>>>
>>> tvm.testing.ErrorTest(1, 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/path/to/tvm/python/tvm/_ffi/_ctypes/function.py", line 190, in __call__
raise get_last_ffi_error()
tvm.error.InternalError: Traceback (most recent call last):
[bt] (3) /path/to/tvm/build/libtvm.so(TVMFuncCall+0x48) [0x7fab500b8ca8]
[bt] (2) /path/to/tvm/build/libtvm.so(+0x1c4126) [0x7fab4f7f5126]
[bt] (1) /path/to/tvm/build/libtvm.so(+0x1ba35c) [0x7fab4f7eb35c]
[bt] (0) /path/to/tvm/build/libtvm.so(+0x177d12) [0x7fab4f7a8d12]
File "/path/to/tvm/src/api/api_test.cc", line 83
InternalError: cannot reach here
TVM hint: You hit an internal error. Please open a thread on https://discuss.tvm.ai/ to report it.
正如您在上面的示例中看到的,TVM 的 ffi 系统将 Python 和 C++ 的堆栈跟踪组合成单个消息,并自动生成相应的错误类。
如何选择错误类型
您可以浏览下面列出的错误类型,尝试使用常识,并参考现有代码中的选择。我们尝试保持合理数量的错误类型。如果您认为需要添加新的错误类型,请执行以下步骤
发送 RFC 提案,其中包含当前代码库中的描述和用例示例。
将新的错误类型添加到
tvm.error
,并提供清晰的文档。更新此文件中的列表以包含新的错误类型。
更改代码以使用新的错误类型。
我们还建议在创建简短错误消息时减少抽象。这样代码更具可读性,并且也为在必要时制作特定的错误消息开辟了道路。
def preferred():
# Very clear about what is being raised and what is the error message.
raise OpNotImplemented("Operator relu is not implemented in the MXNet frontend")
def _op_not_implemented(op_name):
return OpNotImplemented("Operator {} is not implemented.").format(op_name)
def not_preferred():
# Introduces another level of indirection.
raise _op_not_implemented("relu")
如果我们需要引入一个包装函数来构造多行错误消息,请将包装器放在同一文件中,以便其他开发人员可以轻松查找实现。