错误处理指南
TVM包含结构化的错误类来指示特定类型的错误。
请尽可能抛出具体的错误类型,这样用户在必要时可以编写代码来处理特定的错误类别。
在Python中您可以直接抛出具体的错误对象。
在C++等其他语言中,您只需在错误消息前添加前缀(如下所示)。
注意
请参考tvm.error查看错误列表。
在C++中抛出特定错误
您可以在错误信息前添加前缀来抛出对应类型的错误。
请注意,当消息中没有错误类型前缀时,默认会抛出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")
如果需要引入一个构造多行错误消息的包装函数,请将包装函数放在同一文件中,以便其他开发者可以轻松查阅实现。