-
Notifications
You must be signed in to change notification settings - Fork 83
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
Make exceptions from user code more readable #1460
base: main
Are you sure you want to change the base?
Changes from 5 commits
a39afec
2a9d738
0b618c1
f270ad4
4c7d7be
69221b7
1e02e0a
1ac4664
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,7 +71,7 @@ | |
AnyProxy, | ||
) | ||
from thunder.core.interpreter import print_interpreter_log, print_to_log | ||
from thunder.core.jit_ext import thunder_general_jit | ||
from thunder.core.jit_ext import thunder_general_jit, InnerException | ||
from thunder.executors.torch_autograd import split_forward_backward, ThunderFunction | ||
|
||
# NOTE This import is intentionally pytorch so that it thunder.torch doesn't import this | ||
|
@@ -814,7 +814,50 @@ def maybe_call_epilogue(cache_entry, result, pro_to_epi): | |
|
||
return result | ||
|
||
def unwrap_inner_exception(c: Callable) -> Callable: | ||
def _thunder_unwrap_inner_exception(*args, **kwargs): | ||
# Run the function, and caputre the exception if there is one. | ||
try: | ||
return c(*args, **kwargs) | ||
except InnerException as e: | ||
exc = e.value | ||
|
||
def internal_to_thunder(co): | ||
if co is thunder_general_jit.__code__ or co is _thunder_unwrap_inner_exception.__code__: | ||
return True | ||
return co.co_filename.endswith("thunder" + os.sep + "core" + os.sep + "interpreter.py") and ( | ||
co.co_name in ("fn_", "fn_2") | ||
) | ||
Comment on lines
+828
to
+830
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If we drop all interpreter methods, we likely want to keep internal frames at the top of the stacktrace. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Excluding everything in But using As for the functions filtered out by code object, those live outside of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which functions we want to filter does not have an f_globals with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
⚡ ap-readable_exceptions ~/lightning-thunder python exctest.py
Traceback (most recent call last):
File "/teamspace/studios/this_studio/lightning-thunder/exctest.py", line 14, in <module>
jfn()
File "/teamspace/studios/this_studio/lightning-thunder/thunder/__init__.py", line 836, in _thunder_unwrap_inner_exception
assert hasattr(tb.tb_frame.f_globals, "__name__"), tb.tb_frame.f_code.co_name
AssertionError: thunder_general_jit There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's because f_globals is a mapping, so it's members, not attributes. |
||
|
||
# Iterate over the traceback and collect frames that don't correspond to thunder internal functions. | ||
tb = exc.__traceback__ | ||
tb_frames = [] | ||
while tb != None: | ||
co = tb.tb_frame.f_code | ||
if not internal_to_thunder(co): | ||
tb_frames.append(tb) | ||
tb = tb.tb_next | ||
|
||
# Relink the non-internal traceback frames | ||
if tb_frames: | ||
top_tb = tb = tb_frames[0] | ||
for _tb in tb_frames[1:]: | ||
tb.tb_next = _tb | ||
tb = _tb | ||
exc.__traceback__ = top_tb | ||
|
||
# Re-raise the exception without retaining it in this stack frame to avoid leaking tensors. | ||
try: | ||
raise exc | ||
except Exception as e: | ||
nohalon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
del exc | ||
del e | ||
raise # re-raises current exception | ||
|
||
return _thunder_unwrap_inner_exception | ||
|
||
@wraps(fn) | ||
@unwrap_inner_exception | ||
@update_call_statistics | ||
def fn_(*args, **kwargs) -> Any: | ||
if is_tracing(): | ||
|
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 wonder if this could live in the interpreter instead.
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.
The function can. The unwrapping actually can't, tried that already. Traceback frames are pushed as the stack unwinds, not when the exception is thrown.