Repository navigation
perf(binding): cache identical measure requests - #45
Merged
Merged
Conversation
Copilot stopped reviewing on behalf of
hyfdev due to an error
August 17, 2026 14:10
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.
Summary
MeasureSessioncreated for eachcomputeLayoutWithMeasure()f32bit patternsRoot cause
Taffy can issue the same measure request repeatedly during one layout computation. The binding rebuilt
MeasureArguments, converted the complete Style snapshot, crossed Node-API or WASI, and called JavaScript for every repeat even though the node and all constraints were identical.In the coding-agent chat initial-layout scenario, 3,420 Taffy requests collapse to 1,262 exact request combinations.
Implementation
Each raw measured compute already creates a fresh
MeasureSession. The session now owns aHashMap<MeasureCacheKey, Size<f32>>, so its entries are dropped automatically when that compute returns.The key contains:
Noneversus exactf32::to_bits()Definite(bits),MinContent, andMaxContentThe failure check remains first, so a failed session continues to drain later Taffy requests with zero sizes. A result is inserted only after the JavaScript call and conversion to
Size<f32>both succeed. Callback throws and binding conversion failures are not cached; subtree invalidation and original thrown-value identity remain unchanged.No cache survives into another compute, and this does not add Style snapshots, dirtying rules, algorithm changes, or a public API.
Performance
Measured on Node v24.19.0, Linux x64, Intel Core i5-13500H. Each latency is the median of three independent local benchmark runs.
@taffyjs/node@taffyjs/wasmThe public measure callback count changed from 3,420 to 1,262 for both Native and WASI. Temporary counting code was removed before commit.
A complete local benchmark run showed no obvious regression in the three scenarios without measurement callbacks. The measured viewport-resize scenario also improved from 19.0808 ms to 8.8367 ms for Native and from 158.6806 ms to 65.7667 ms for WASI relative to the same-machine published baseline.
Validation
vp run check— passed, including format, type-aware lint, Clippy, 10 Rust tests, 204 Native public behavior tests, native binding tests, type tests, and Yoga testsvp run check:wasm— passed, including the same 204 public behavior tests on WASI, browser runtime/bundle checks, type/package checks, packed consumers, Yoga WASI, and website buildvp run benchmark --scenario=coding-agent-chat-initial-layout— three runs before and three runs after; medians reported abovevp run benchmark— complete local suite passed with equivalent layout validationFixes #38