Micro pass over the diff hot paths: skip-equal keys, shared pointers, exact-class dispatch#56
Merged
Merged
Conversation
7f46ac8 to
271b3d3
Compare
ddbf849 to
4aba07c
Compare
271b3d3 to
6a60c03
Compare
… exact-class dispatch
- diff_dicts: compare common-key values before recursing - equal values
used to pay a diff() call plus a child Pointer allocation just to
return an empty result, which was most of the work when few of many
common keys changed; changed values now pay one extra (fail-fast)
compare instead
- diff_sets: one shared "-" pointer for all add operations (pointers
are immutable) instead of allocating one per element, and a bound
ptr.append for the removes
- diff(): dispatch on exact classes first with an atomic-type
short-circuit, keeping the hasattr chain as the fallback for
container look-alikes such as observ proxies; scalar replace leaves
no longer pay up to six hasattr calls
Interleaved benchmark medians vs the Myers branch (2 runs each):
dict_diff_flat_500_keys 243.5us -> 86.7us (-64.5%)
set_diff_1000_elements 70.9us -> 49.3us (-31.0%)
mixed_dict_with_lists 123.3ms -> 124.6ms (-8.1% on mean medians)
dict_diff_large_common +0.9..+1.9% (every common key changed, so
the pre-check never skips; fail-fast cost)
dict_diff_nested +3.8% (same, on nested values)
pointer benchmarks unchanged
An indexing rewrite of Pointer.evaluate was tried and rejected: it
benchmarked 18-26% slower than iterating the tokens[:-1] slice.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Mu9vEBwU4fQLi8ZgkgdS2
6a60c03 to
1d60335
Compare
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 11 — the diff/pointer micro pass. Rebased onto
masternow that #53 (Myers) and #52 (typecheck fix) are merged — this diff is now just the micro-pass commit on its own.What
diff_dicts: compare common-key values before recursing. Equal values used to pay adiff()call plus a childPointerallocation just to return an empty result — which was most of the work when few of many common keys changed. Changed values now pay one extra fail-fast compare instead.diff_sets: one shared-pointer for all add operations (pointers are immutable, so sharing is safe) instead of allocating one per element, plus a boundptr.appendfor removes.diff(): exact-class dispatch first with an atomic-type short-circuit; thehasattrchain stays as the fallback for container look-alikes such as observ proxies. Scalar replace leaves no longer pay up to sixhasattrcalls.Benchmarks
Interleaved medians vs the Myers branch, 2 runs each:
The small upticks are the honest cost of the skip-equal pre-check on workloads where every common key changed (the pre-check never skips, and
diff()re-compares) — a few percent against −64% when keys are mostly unchanged, which is the common real-world shape.Negative result, documented: an indexing rewrite of
Pointer.evaluate(avoiding thetokens[:-1]slice copy) benchmarked 18–26% slower — tuple-slice iteration beats indexed access in CPython — and was rejected;pointer.pyis untouched by this PR.407 tests at 100% coverage, ruff and ty clean.
🤖 Generated with Claude Code
https://claude.ai/code/session_016Mu9vEBwU4fQLi8ZgkgdS2