Title: Disable automatic update of frame locals during tracing
Type: performance Stage: patch review
Components: Interpreter Core Versions: Python 3.10
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: fabioz, python-dev, vstinner
Priority: normal Keywords: patch

Created on 2020-10-29 14:16 by fabioz, last changed 2020-10-29 21:01 by vstinner.

Pull Requests
URL Status Linked Edit
PR 23028 open python-dev, 2020-10-29 15:41
Messages (1)
msg379874 - (view) Author: Fabio Zadrozny (fabioz) * Date: 2020-10-29 14:16
Right now, when a debugger is active, the number of local variables can affect the tracing speed quite a lot.

For instance, having tracing setup in a program such as the one below takes 4.64 seconds to run, yet, changing all the variables to have the same name -- i.e.: change all assignments to `a = 1` (such that there's only a single variable in the namespace), it takes 1.47 seconds (in my machine)... the higher the number of variables, the slower the tracing becomes.

import time
t = time.time()

def call():
    a = 1
    b = 1
    c = 1
    d = 1
    e = 1
    f = 1

def noop(frame, event, arg):
    return noop

import sys

for i in range(1_000_000):

print('%.2fs' % (time.time() - t,))

This happens because `PyFrame_FastToLocalsWithError` and `PyFrame_LocalsToFast` are called inside the `call_trampoline` (

So, I'd like to simply remove those calls.

Debuggers can call  `PyFrame_LocalsToFast` when needed -- otherwise mutating non-current frames doesn't work anyways. As a note, pydevd already has such a call: and PyPy also has a counterpart.

As for `PyFrame_FastToLocalsWithError`, I don't really see any reason to call it at all.

i.e.: something as the code below prints the `a` variable from the `main()` frame regardless of that and I checked all pydevd tests and nothing seems to be affected (it seems that accessing f_locals already does this:, so, I don't see much reason to call it at all).

def call():
    import sys
    frame = sys._getframe()
def main():
    a = 1
if __name__ == '__main__':

So, the idea is removing those lines (I expect that I'll be able to provide a pull request for this).
Date User Action Args
2020-10-29 21:01:29vstinnersetnosy: + vstinner
2020-10-29 15:41:05python-devsetkeywords: + patch
nosy: + python-dev

pull_requests: + pull_request21947
stage: patch review
2020-10-29 14:16:41fabiozcreate