Skip to content

inspect.getframeinfo and traceback build every preceding co_positions() tuple #161799

Open

Description

@xionghul

Bug report

inspect.getframeinfo() and traceback read the position of the current instruction with:

next(itertools.islice(code.co_positions(), instruction_index // 2, None))

co_positions() yields one tuple per instruction. islice has to build and discard a tuple for every preceding instruction before it can return the requested one. The returned position is correct. The cost grows with the size of the code object.

inspect.stack(0) does this for every frame. context=0 only skips the source-line listing. It still computes the PEP 657 position. A caller that uses inspect.stack(0) on a hot path therefore pays for a full walk of each frame's line table.

On 3.11 and on current main, a short function and a function with about 2500 statements show the difference:

import inspect
import timeit

def make(n):
    src = "def f():\n" + "    x = 1\n" * n + "    return inspect.stack(0)\n"
    ns = {"inspect": inspect}
    exec(src, ns)
    return ns["f"]

small, large = make(10), make(2500)
print("small", timeit.timeit(small, number=2000) / 2000)
print("large", timeit.timeit(large, number=200) / 200)

The byte offset passed in is f_lasti or tb_lasti, the same value traceback.c already passes to PyCode_Addr2Location. One call of that function fills the same (start_line, end_line, start_column, end_column) tuple, with None where co_positions() yields None.

A direct lookup for real code objects removes the per-instruction tuple. Objects that only implement co_positions(), such as the stand-ins in test_traceback, can keep the iterator path.

CPython versions tested on:

3.11, CPython main branch

Operating systems tested on:

No response

Linked PRs

Activity

  1. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Nov 11, 2026
  2. picnixz commented on Nov 11, 2026

    @picnixz
    Member

    I'm not convinced by this change. How "slow" is it? those are inspection tools and thus I don't think we should add private C methods just for that.

  3. added
    type-featureA feature request or enhancement
    performancePerformance or resource usage
    pendingThe issue will be closed if no feedback is provided
    and removed
    type-bugAn unexpected behavior, bug, or error
    on Nov 11, 2026
  4. picnixz commented on Nov 11, 2026

    @picnixz
    Member

    On 3.11 and on current main, a short function and a function with about 2500 statements show the difference:

    Please post the actual numbers. Determine whether they were done on a PGO+LTO/release build. Debug builds are not relevant when it comes down to performance evaluation.

  5. xionghul commented on Nov 12, 2026

    @xionghul
    Author

    small 0.00013875
    large 0.00074843

    3.11.6 (main, Oct 3 2023, 01:26:22) [Clang 17.0.1] with PGO+LTO/release build.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    pendingThe issue will be closed if no feedback is providedperformancePerformance or resource usagestdlibStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions