Cut per-call overhead in the produce proxy traps#57
Merged
Conversation
Korijn
force-pushed
the
claude/produce-hotpath
branch
2 times, most recently
from
July 11, 2026 10:46
1d172c7 to
044f769
Compare
Korijn
force-pushed
the
claude/produce-micro
branch
from
July 11, 2026 10:46
f859b50 to
8a21b2d
Compare
Collaborator
Author
|
@berendkleinhaneveld I'll let you review & approve this one |
Korijn
force-pushed
the
claude/produce-hotpath
branch
from
July 11, 2026 10:54
044f769 to
f5e4fe8
Compare
Korijn
force-pushed
the
claude/produce-micro
branch
from
July 11, 2026 10:55
8a21b2d to
96e5166
Compare
Korijn
force-pushed
the
claude/produce-micro
branch
from
July 11, 2026 11:00
5197c6c to
eec5507
Compare
Trap-level micro pass (Track E), on top of the location memoization:
- Scalar fast path in _wrap: scalar reads skip the cache lookup and
the hasattr chain entirely (scalars never have a cached child proxy:
cache entries only exist for container values), inlined additionally
in DictProxy/ListProxy __getitem__ for the hottest read shape
- DictProxy.__setitem__ resolves the old value with one sentinel
data.get() instead of a containment check plus a read - two trapped
operations become one when the draft wraps an observ proxy
- values()/items() iterate _data.items() once instead of re-reading
every key, with the scalar check inlined; ListProxy __iter__ and
__reversed__ get the same treatment plus bound locals
- ListProxy.append and the slice read path bind hot attributes to
locals and drop intermediate temporaries
Two small tests added for the new early-return paths (scalar list
reads by index, tuple values through _wrap), keeping coverage at 100%.
Interleaved benchmark medians vs the memoization branch (2 runs each):
produce_in_place_vs_copy_dict (writes through an
observ reactive draft) 192.3us -> 156.6us (-18.6%)
produce_list_many_appends -1.8% / -2.0%
everything else within noise (+/-1.5%)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Mu9vEBwU4fQLi8ZgkgdS2
Korijn
force-pushed
the
claude/produce-micro
branch
from
July 13, 2026 07:13
7f4e219 to
cea03cc
Compare
berendkleinhaneveld
approved these changes
Jul 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Track E, PR 13 — the trap-level micro pass, the analog of observ #192/#193.
What
_wrap: scalar reads skip the child-proxy cache lookup and thehasattrchain entirely (scalars never have a cached child proxy — cache entries only exist for container values). Inlined additionally inDictProxy/ListProxy__getitem__for the hottest read shape.DictProxy.__setitem__resolves the old value with one sentineldata.get()instead of a containment check plus a read. On plain dicts that's a wash, but when the draft wraps an observ reactive proxy (in_place=True), each of those was a trapped operation with dep tracking — two trapped calls become one.values()/items()iterate_data.items()once instead of re-reading every key, with the scalar check inlined;ListProxy.__iter__/__reversed__get the same treatment plus bound locals.ListProxy.appendand the slice read path bind hot attributes to locals and drop intermediate temporaries.Two small tests are added for the new early-return paths (scalar list reads by index, tuple values through
_wrap), keeping coverage at 100%. Behavior is unchanged; 408 tests pass, ruff and ty clean.Benchmarks
Interleaved medians vs the memoization branch (#54), 2 runs each:
An honest note on magnitude: the write-heavy plain-dict workloads were already lean (the sentinel-get trades two
dictlookups for one method call, which is a wash on plain dicts), so the wins concentrate where the pass targets — read paths and proxy-backed drafts.🤖 Generated with Claude Code
https://claude.ai/code/session_016Mu9vEBwU4fQLi8ZgkgdS2