Skip to content

Release 1.0.3: store active-section frames as plain tuples - #22

Merged
seba2390 merged 1 commit into
mainfrom
perf/plain-tuple-frames
Sep 30, 2026
Merged

seba2390 merged 1 commit into
mainfrom
perf/plain-tuple-frames

Conversation

@seba2390

Copy link
Copy Markdown
Owner

What does this change?

Performance. Every section entry built a _Frame NamedTuple, whose constructor runs in Python and costs about 190 ns. That's more than the rest of section entry combined; a plain tuple costs about 30 ns. _Frame is now a type alias for a plain tuple, unpacked where it's read. It's internal only, so the public API and behaviour are the same.

Measured back to back on CPython 3.14.5 (macOS, ARM64), in µs per operation:

Operation 1.0.2 1.0.3 Faster
New context 1.116 0.877 21%
Reused context 1.013 0.786 22%
Decorated call 1.220 0.897 26%
Decorated await 1.197 0.948 21%
Five nested contexts 5.782 4.371 24%

It's a similar 13–20% on 3.11 and on free-threaded 3.14t. Reporting paths are unchanged.

I also tried inlining the timer logic into TimerContext.__enter__. It gained only 2–7%, within noise, so I left it out. What's left of the cost is the lock, the ContextVar and perf_counter calls, which the thread and async safety depend on.

Docs: benchmarks/README.md now compares 0.1.0, 1.0.2 and 1.0.3, measured one after the other on the same interpreter. The docs overhead page includes this table.

Release: bumps __version__ to 1.0.3 and moves the unreleased documentation-site entries into 1.0.3. Publishing it updates the PyPI page with the shorter README and adds the Documentation link.

Checklist

  • uv run pytest --cov passes (112 tests, 100% statement and branch coverage). It also passes locally on 3.12, 3.13, 3.14 and 3.14t.
  • uv run ruff check and uv run ruff format --check pass
  • uv run basedpyright passes (0 errors, 0 warnings)
  • Behaviour changes are covered by a test: no behaviour change; the existing suite covers every frame path
  • CHANGELOG.md updated
  • uv build and twine check --strict pass, the wheel reports 1.0.3, and the Sphinx build passes with -W -n.

Constructing the _Frame NamedTuple ran a Python-level __new__ that cost
about 190 ns, more than the rest of section entry combined. A plain tuple
costs about 30 ns, making entering and exiting a section 20-25% faster
across 3.11, 3.14 and free-threaded 3.14t. Behaviour is unchanged.

Also refresh the overhead benchmark with 0.1.0, 1.0.2 and 1.0.3 measured
back to back, and release the documentation site changes, so the PyPI
page gets the shorter README and the Documentation link.
@seba2390
seba2390 merged commit 5b548d7 into main Sep 30, 2026
19 checks passed
@seba2390
seba2390 deleted the perf/plain-tuple-frames branch September 30, 2026 21:48
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.

1 participant