[Python-Dev] PyCharm debugger became 40x faster on Python 3.6 thanks to PEP 523

Xavier de Gaye xdegaye at gmail.com
Mon Mar 27 15:48:08 EDT 2017


On 03/25/2017 08:57 PM, Terry Reedy wrote:
 > On 3/25/2017 8:56 AM, Serhiy Storchaka wrote:
 >> On 25.03.17 12:04, Victor Stinner wrote:
 >>> https://blog.jetbrains.com/pycharm/2017/03/inside-the-debugger-interview-with-elizaveta-shashkova/
 >>>
 >>>
 >>> "What changed in Python 3.6 to allow this?
 >>>
 >>> The new frame evaluation API was introduced to CPython in PEP 523 and it
 >>> allows to specify a per-interpreter function pointer to handle the
 >>> evaluation of frames."
 >>>
 >>> Nice!
 >>
 >> Awesome! Any chance that pdb can utilize similar technique? Or this
 >> doesn't make sense for pdb?
 >
 > According to the bdb.Bdb docstring, pdb implements a command-line user interface on top of bdb, while  bdb.Bdb "takes care of the details of the trace facility".  idlelib.debugger similarly implements
 > a GUI user interface on top of bdb.  I am sure that there are other debuggers that build directly or indirectly (via pdb) on bdb.  So the question is whether bdb can be enhanced or augmented with a
 > C-coded _bdb or other new module.
 >
 > As I understand it, sys.settrace results in an execution break and function call at each point in the bytecode corresponding to the beginning of a (logical?) line.  This add much overhead.  In return,
 > a trace-based debugger allows one to flexibly control stop and go execution either with preset breakpoints* or with interactive commands: step (one line), step into (a function frame), step over (a
 > function frame), or go to next breakpoint.  The last is implemented by the debugger automatically stepping at each break call unless the line is in the existing breakpoint list.
 >
 > * Breakpoints can be defined either in an associated editor or with breakpoint commands in the debugger when execution is stopped.
 >
 > PEP 523 envisioned an alternate non-trace implementation of 'go to next breakpoint' by a debugger going "as far as to dynamically rewrite bytecode prior to execution to inject e.g. breakpoints in the
 > bytecode."
 > https://www.python.org/dev/peps/pep-0523/#debugging
 >
 > A debugger doing this could either eliminate the other 'go' commands (easiest) or implement them by either setting temporary breakpoints or temporarily turning tracing on.
 >
 > I presume it should be possible to make bdb.Bdb use bytecode breakpoints or add a new class with a similar API.  Then any bdb-based debugger to be modified to make the speedup available.


pdb-clone, an extension to pdb, gets about those same performance gains over
pdb while still using sys.settrace(). pdb-clone runs at a speed of less than
twice the speed of the interpreter when pdb runs at about 80 times the speed
of the interpreter. See some performance measurements at
https://bitbucket.org/xdegaye/pdb-clone/wiki/Performances.md

Given those results, it is not clear how one would get a boost of a factor 40
by implementing PEP 523 for the pdb debugger as pdb could already be very
close to the speed of the interpreter mostly by implementing in a C extension
module the bdb.Bdb methods that check whether the debugger should take
control.

Setting a trace function with sys.settrace() adds the following incompressible overhead:
* 15-20 % overhead: computed goto are not used in the ceval loop when tracing is active.
* The trace function receives all the PyTrace_LINE events (even when the frame
   f_trace is NULL :(). The interpreter calls _PyCode_CheckLineNumber() for
   each of these events and the processing in this function is the one that is
   costly. An optimization is done in pdb-clone that swaps the trace function
   with a profiler function whenever possible (i.e. when there is no need to
   trace the lines of the function) to avoid calling _PyCode_CheckLineNumber()
   (the profiler still gets PyTrace_C_CALL events but there is not such
   overhead with these events).  The performance gain obtained with this scheme
   is about 30%.

I think that the main point here is not whether to switch from sys.settrace()
to PEP 523, but first to implement the stop_here() bdb.Bdb method in a C
extension module.

Xavier



More information about the Python-Dev mailing list