-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RUNTIME] Scaffold structured error handling. #2838
Conversation
Thanks @tqchen for the effort. This is amazing! I think this is a great setup for unified error messages. I particularly like the way to unify C++ and Python stack traces. |
cc @KoinFlyp @wweic |
Sounds like a plan |
see also wrapper vs less-abstraction discussion in #2279 |
This is a perfect solution when all exceptions defined don't carry extra information besides their own types, and I don't think there is usecase for now that an exception would carry extra information. So I agree with the high-level idea. Rushing for a paper deadline, will review the detailed implementation tomorrow night. |
python/tvm/error.py
Outdated
|
||
|
||
@register_error | ||
class OpNotImplemented(OpError): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, I like how the Python and C++ error handling is unified. Should OpNotImplemented
also inherit NotImplementedError
? In case one is trying to catch specific error types, e.g., to gather a list of all operators or attributes that are unsupported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, just some suggestions regarding the exception hierarchy.
|
||
.. code:: python | ||
|
||
def preferred(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not completely sure about which of these are preferred. Is only the first option valid? Option 2 is not preferred, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
more discussions in #2279, i think this is something that maybe worth some more discussion
python/tvm/_ffi/base.py
Outdated
|
||
def _valid_error_name(name): | ||
"""Check whether name is a valid error name.""" | ||
return all(x.isalnum() or x == '_' or x == '.' for x in name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: return all(x.isalnum() or x in '_.' for x in name)
docs/contribute/error_handling.rst
Outdated
|
||
How to choose an Error Type | ||
--------------------------- | ||
You can go through the error types are listed below, try to us common |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: us->use
docs/contribute/error_handling.rst
Outdated
raise OpNotImplemented("Operator relu is not implemented in the MXNet fronend") | ||
|
||
def _op_not_implemented(op_name): | ||
return OpNotImpelemented("Operator {} is not implemented.").format(op_name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Impelemented->Implemented
python/tvm/error.py
Outdated
|
||
@register_error | ||
class OpError(TVMError): | ||
"""Base class of all operator errors in fronends.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: fronends->frontends
python/tvm/error.py
Outdated
|
||
|
||
@register_error | ||
class OpNotImplemented(OpError): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest class OpNotImplementedError(OpError, NotImplementedError):
python/tvm/error.py
Outdated
|
||
|
||
@register_error | ||
class OpAttributeRequired(OpError): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest class OpAttributeRequiredError(OpError, AttributeError):
python/tvm/error.py
Outdated
|
||
|
||
@register_error | ||
class OpAttributeInvalid(OpError): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest class OpAttributeInvalidError(OpError, AttributeError):
python/tvm/error.py
Outdated
|
||
|
||
@register_error | ||
class OpAttributeUnimplemented(OpError): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest class OpAttributeNotImplementedError(OpError, AttributeError, NotImplementedError):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks, @yidawang @KoinFlyp @junrushao1994, this is now merged |
Given that there is some enough interest in structured error handling #2279 and we want to have a guideline to resolve the tension of simplicity and structures. This PR attempts to provide a minimum scaffold toward that step.
New Error Messages
One thing that I like to highlight is that this PR allows us to simply use
LOG(FATAL) << "ErrorType: message
to throw a specific error out.We also combine the python/c++ stack trace in a reasonable way so that the error message is more human-friendly. The error message itself contains the traceback in C++ function and can be read naturally when combined with the python traceback. We also make it work for callbacks.
Example C++ code:
The above function is registered as PackedFunc into the python frontend,
under the name
tvm._api_internal._ErrorTest
.Here is what will happen if we call the registered function:
It also works with recursive callbacks between python->c++->python