Skip to content

gh-150942: Speed up frame local item collection#151002

Merged
corona10 merged 3 commits into
python:mainfrom
omkar-334:speed-up-frame-locals-items
Jun 7, 2026
Merged

gh-150942: Speed up frame local item collection#151002
corona10 merged 3 commits into
python:mainfrom
omkar-334:speed-up-frame-locals-items

Conversation

@omkar-334
Copy link
Copy Markdown
Contributor

@omkar-334 omkar-334 commented Jun 6, 2026

Use _PyList_AppendTakeRef while collecting frame-local (name, value) pairs
instead of PyList_Append followed by Py_DECREF, removing an incref/decref
pair per returned item pair.

benchmarks

Benchmark main this PR speedup
frame_locals_items_100locals 9.09 ms 8.61 ms 1.06x
frame_locals_items_1000locals 17.19 ms 16.59 ms 1.04x
frame_locals_items_5000locals 29.92 ms 28.94 ms 1.03x
geomean 1.04x
Benchmark script
"""Micro-benchmark for frame.f_locals.items() result-list building."""

from __future__ import annotations

import argparse
import json
import statistics
import sys
import time
from pathlib import Path


def make_frame(local_count: int):
    assignments = "\n".join(f"    v{i} = {i}" for i in range(local_count))
    src = (
        "def make_frame():\n"
        f"{assignments}\n"
        "    return sys._getframe()\n"
    )
    ns = {"sys": sys}
    exec(src, ns)
    return ns["make_frame"]()


def time_items(frame, loops: int) -> float:
    t0 = time.perf_counter_ns()
    for _ in range(loops):
        frame.f_locals.items()
    return (time.perf_counter_ns() - t0) / 1e9


def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--locals", type=int, default=1_000)
    ap.add_argument("--loops", type=int, default=2_000)
    ap.add_argument("--trials", type=int, default=15)
    ap.add_argument("--warmup", type=int, default=3)
    ap.add_argument("--label", default="run")
    ap.add_argument("--outdir", default="results/frame-locals-items")
    args = ap.parse_args()

    frame = make_frame(args.locals)
    item_count = len(frame.f_locals.items())

    for _ in range(args.warmup):
        time_items(frame, args.loops)

    trials = [time_items(frame, args.loops) for _ in range(args.trials)]

    outdir = Path(args.outdir)
    outdir.mkdir(parents=True, exist_ok=True)
    summary = {
        "label": args.label,
        "python": sys.executable,
        "locals": args.locals,
        "item_count": item_count,
        "loops": args.loops,
        "trials": args.trials,
        "warmup": args.warmup,
        "items_built": item_count * args.loops,
        "seconds": {
            "min": min(trials),
            "median": statistics.median(trials),
            "mean": statistics.fmean(trials),
            "stdev": statistics.pstdev(trials),
            "all": trials,
        },
        "items_per_sec_at_min": (item_count * args.loops) / min(trials),
    }
    out = outdir / f"bench_{args.label}.json"
    out.write_text(json.dumps(summary, indent=2))

    s = summary["seconds"]
    print(
        f"{args.label}: min={s['min']*1000:.2f}ms median={s['median']*1000:.2f}ms "
        f"mean={s['mean']*1000:.2f}ms stdev={s['stdev']*1000:.2f}ms "
        f"items/s@min={summary['items_per_sec_at_min']:.2e}"
    )
    print(f"wrote {out}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

@omkar-334 omkar-334 requested a review from markshannon as a code owner June 6, 2026 03:01
@omkar-334 omkar-334 changed the title Speed up frame local item collection gh-150942: Speed up frame local item collection Jun 6, 2026
Comment thread Misc/NEWS.d/next/Core_and_Builtins/2026-06-06-08-20-00.gh-issue-150942.Jk9pQr.rst Outdated
Copy link
Copy Markdown
Contributor

@sergey-miryanov sergey-miryanov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Copy Markdown
Member

@corona10 corona10 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm with the following perspectives.
: The PR makes code simpler with performance improvement.

@corona10 corona10 merged commit 253904f into python:main Jun 7, 2026
59 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants