Description
Is there an existing proposal for this?
- I have searched the existing proposals
Is your feature request related to a problem?
We default to showing pure Python stacks, both for performance and for legibility to people who aren't systems programmers, but often these aren't very useful for figuring out exactly why a program had a hang or crash, since it's not always clear what might be happening inside of the current Python call. The solution to this is running with --native
or --native-all
mode, but these modes are both very verbose.
Describe the solution you'd like
@alicederyn has pitched an idea for me: it might be possible to eliminate some of the noise and performance implications of --native
mode while still providing enough information to puzzle out deadlocks or blocking happening in the C code called from the user's Python code if have a mode that only shows the C frames after the last Python frame. That is, instead of our pure-Python stacks:
Traceback for thread 112 [] (most recent call last):
(Python) File "/test.py", line 17, in <module>
first_func()
(Python) File "/test.py", line 6, in first_func
second_func()
(Python) File "/test.py", line 10, in second_func
third_func()
(Python) File "/test.py", line 14, in third_func
time.sleep(1000)
And instead of the hybrid stacks that we show with --native
:
Traceback for thread 112 [] (most recent call last):
(C) File "???", line 0, in _start ()
(C) File "???", line 0, in __libc_start_main ()
(C) File "Modules/main.c", line 743, in Py_BytesMain (/usr/lib/libpython3.8.so.1.0)
(C) File "Modules/main.c", line 689, in Py_RunMain (/usr/lib/libpython3.8.so.1.0)
(C) File "Modules/main.c", line 610, in pymain_run_python (inlined) (/usr/lib/libpython3.8.so.1.0)
(C) File "Modules/main.c", line 385, in pymain_run_file (inlined) (/usr/lib/libpython3.8.so.1.0)
(C) File "Python/pythonrun.c", line 472, in PyRun_SimpleFileExFlags (/usr/lib/libpython3.8.so.1.0)
(C) File "Python/pythonrun.c", line 439, in pyrun_simple_file (inlined) (/usr/lib/libpython3.8.so.1.0)
(C) File "Python/pythonrun.c", line 1085, in pyrun_file (/usr/lib/libpython3.8.so.1.0)
(C) File "Python/pythonrun.c", line 1188, in run_mod (/usr/lib/libpython3.8.so.1.0)
(C) File "Python/pythonrun.c", line 1166, in run_eval_code_obj (/usr/lib/libpython3.8.so.1.0)
(Python) File "/test.py", line 17, in <module>
first_func()
(C) File "Python/ceval.c", line 4963, in call_function (inlined) (/usr/lib/libpython3.8.so.1.0)
(C) File "Objects/call.c", line 284, in function_code_fastcall (inlined) (/usr/lib/libpython3.8.so.1.0)
(Python) File "/test.py", line 6, in first_func
second_func()
(C) File "Python/ceval.c", line 4963, in call_function (inlined) (/usr/lib/libpython3.8.so.1.0)
(C) File "Objects/call.c", line 284, in function_code_fastcall (inlined) (/usr/lib/libpython3.8.so.1.0)
(Python) File "/test.py", line 10, in second_func
third_func()
(C) File "Python/ceval.c", line 4963, in call_function (inlined) (/usr/lib/libpython3.8.so.1.0)
(C) File "Objects/call.c", line 284, in function_code_fastcall (inlined) (/usr/lib/libpython3.8.so.1.0)
(Python) File "/test.py", line 14, in third_func
time.sleep(1000)
(C) File "Python/ceval.c", line 4963, in call_function (inlined) (/usr/lib/libpython3.8.so.1.0)
(C) File "Modules/timemodule.c", line 338, in time_sleep (/usr/lib/libpython3.8.so.1.0)
(C) File "Modules/timemodule.c", line 1866, in pysleep (inlined) (/usr/lib/libpython3.8.so.1.0)
(C) File "???", line 0, in __select ()
We'd show a stack that switches to showing C frames automatically after the last Python frame:
Traceback for thread 112 [] (most recent call last):
(Python) File "/test.py", line 17, in <module>
first_func()
(Python) File "/test.py", line 6, in first_func
second_func()
(Python) File "/test.py", line 10, in second_func
third_func()
(Python) File "/test.py", line 14, in third_func
time.sleep(1000)
(C) File "Python/ceval.c", line 4963, in call_function (inlined) (/usr/lib/libpython3.8.so.1.0)
(C) File "Modules/timemodule.c", line 338, in time_sleep (/usr/lib/libpython3.8.so.1.0)
(C) File "Modules/timemodule.c", line 1866, in pysleep (inlined) (/usr/lib/libpython3.8.so.1.0)
(C) File "???", line 0, in __select ()
This could be faster than running with --native
, as we should be able to avoid unwinding and symbolizing the entire call stack and instead stop when we reach the first _PyEval_EvalFrameDefault
call (though currently we do all the unwinding before any of the symbolizing, and that would need to change if we wanted to break out of unwinding early).
@pablogsal feels this would be a confusing default, but is willing to consider it as a --native=brief
or --native-all=brief
flag.
Alternatives you considered
No response