mirror of
https://github.com/python/cpython.git
synced 2025-08-22 09:45:06 +00:00
bpo-45256: Remove the usage of the C stack in Python to Python calls (GH-28488)
Ths commit inlines calls to Python functions in the eval loop and steals all the arguments in the call from the caller for performance.
This commit is contained in:
parent
ec04db74e2
commit
b4903afd4d
7 changed files with 224 additions and 64 deletions
|
@ -45,6 +45,7 @@ The module also extends gdb with some python-specific commands.
|
|||
# compatible (2.6+ and 3.0+). See #19308.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import gdb
|
||||
import os
|
||||
import locale
|
||||
|
@ -991,6 +992,11 @@ class PyFramePtr:
|
|||
def _f_lasti(self):
|
||||
return self._f_special("f_lasti", int_from_int)
|
||||
|
||||
def depth(self):
|
||||
return self._f_special("depth", int_from_int)
|
||||
|
||||
def previous(self):
|
||||
return self._f_special("previous", PyFramePtr)
|
||||
|
||||
def iter_globals(self):
|
||||
'''
|
||||
|
@ -1797,16 +1803,20 @@ class Frame(object):
|
|||
|
||||
def print_summary(self):
|
||||
if self.is_evalframe():
|
||||
pyop = self.get_pyop()
|
||||
if pyop:
|
||||
line = pyop.get_truncated_repr(MAX_OUTPUT_LEN)
|
||||
write_unicode(sys.stdout, '#%i %s\n' % (self.get_index(), line))
|
||||
if not pyop.is_optimized_out():
|
||||
line = pyop.current_line()
|
||||
if line is not None:
|
||||
sys.stdout.write(' %s\n' % line.strip())
|
||||
else:
|
||||
sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
|
||||
interp_frame = self.get_pyop()
|
||||
while True:
|
||||
if interp_frame:
|
||||
line = interp_frame.get_truncated_repr(MAX_OUTPUT_LEN)
|
||||
write_unicode(sys.stdout, '#%i %s\n' % (self.get_index(), line))
|
||||
if not interp_frame.is_optimized_out():
|
||||
line = interp_frame.current_line()
|
||||
if line is not None:
|
||||
sys.stdout.write(' %s\n' % line.strip())
|
||||
if interp_frame.depth() == 0:
|
||||
break
|
||||
else:
|
||||
sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
|
||||
interp_frame = interp_frame.previous()
|
||||
else:
|
||||
info = self.is_other_python_frame()
|
||||
if info:
|
||||
|
@ -1816,15 +1826,19 @@ class Frame(object):
|
|||
|
||||
def print_traceback(self):
|
||||
if self.is_evalframe():
|
||||
pyop = self.get_pyop()
|
||||
if pyop:
|
||||
pyop.print_traceback()
|
||||
if not pyop.is_optimized_out():
|
||||
line = pyop.current_line()
|
||||
if line is not None:
|
||||
sys.stdout.write(' %s\n' % line.strip())
|
||||
else:
|
||||
sys.stdout.write(' (unable to read python frame information)\n')
|
||||
interp_frame = self.get_pyop()
|
||||
while True:
|
||||
if interp_frame:
|
||||
interp_frame.print_traceback()
|
||||
if not interp_frame.is_optimized_out():
|
||||
line = interp_frame.current_line()
|
||||
if line is not None:
|
||||
sys.stdout.write(' %s\n' % line.strip())
|
||||
if interp_frame.depth() == 0:
|
||||
break
|
||||
else:
|
||||
sys.stdout.write(' (unable to read python frame information)\n')
|
||||
interp_frame = interp_frame.previous()
|
||||
else:
|
||||
info = self.is_other_python_frame()
|
||||
if info:
|
||||
|
@ -1914,11 +1928,15 @@ PyList()
|
|||
|
||||
def move_in_stack(move_up):
|
||||
'''Move up or down the stack (for the py-up/py-down command)'''
|
||||
# Important:
|
||||
# The amount of frames that are printed out depends on how many frames are inlined
|
||||
# in the same evaluation loop. As this command links directly the C stack with the
|
||||
# Python stack, the results are sensitive to the number of inlined frames and this
|
||||
# is likely to change between versions and optimizations.
|
||||
frame = Frame.get_selected_python_frame()
|
||||
if not frame:
|
||||
print('Unable to locate python frame')
|
||||
return
|
||||
|
||||
while frame:
|
||||
if move_up:
|
||||
iter_frame = frame.older()
|
||||
|
@ -1940,9 +1958,10 @@ def move_in_stack(move_up):
|
|||
print('Unable to find an older python frame')
|
||||
else:
|
||||
print('Unable to find a newer python frame')
|
||||
|
||||
|
||||
class PyUp(gdb.Command):
|
||||
'Select and print the python stack frame that called this one (if any)'
|
||||
'Select and print all python stack frame in the same eval loop starting from the one that called this one (if any)'
|
||||
def __init__(self):
|
||||
gdb.Command.__init__ (self,
|
||||
"py-up",
|
||||
|
@ -1954,7 +1973,7 @@ class PyUp(gdb.Command):
|
|||
move_in_stack(move_up=True)
|
||||
|
||||
class PyDown(gdb.Command):
|
||||
'Select and print the python stack frame called by this one (if any)'
|
||||
'Select and print all python stack frame in the same eval loop starting from the one called this one (if any)'
|
||||
def __init__(self):
|
||||
gdb.Command.__init__ (self,
|
||||
"py-down",
|
||||
|
@ -2067,13 +2086,20 @@ class PyLocals(gdb.Command):
|
|||
return
|
||||
|
||||
pyop_frame = frame.get_pyop()
|
||||
if not pyop_frame:
|
||||
print(UNABLE_READ_INFO_PYTHON_FRAME)
|
||||
return
|
||||
while True:
|
||||
if not pyop_frame:
|
||||
print(UNABLE_READ_INFO_PYTHON_FRAME)
|
||||
|
||||
for pyop_name, pyop_value in pyop_frame.iter_locals():
|
||||
print('%s = %s'
|
||||
% (pyop_name.proxyval(set()),
|
||||
pyop_value.get_truncated_repr(MAX_OUTPUT_LEN)))
|
||||
sys.stdout.write('Locals for %s\n' % (pyop_frame.co_name.proxyval(set())))
|
||||
|
||||
for pyop_name, pyop_value in pyop_frame.iter_locals():
|
||||
print('%s = %s'
|
||||
% (pyop_name.proxyval(set()),
|
||||
pyop_value.get_truncated_repr(MAX_OUTPUT_LEN)))
|
||||
|
||||
if pyop_frame.depth() == 0:
|
||||
break
|
||||
|
||||
pyop_frame = pyop_frame.previous()
|
||||
|
||||
PyLocals()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue