Skip to content

perf(binding): cache identical measure requests - #45

Merged
hyfdev merged 1 commit into
mainfrom
codex/measure-session-cache
Aug 17, 2026
Merged

hyfdev merged 1 commit into
mainfrom
codex/measure-session-cache

Conversation

@hyfdev

@hyfdev hyfdev commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Summary

  • cache successful identical measure results inside the Rust MeasureSession created for each computeLayoutWithMeasure()
  • key requests by raw node ID, both optional known dimensions, and both available-space variants and definite f32 bit patterns
  • reuse a hit before creating callback arguments, converting Style, or crossing Node-API/WASI
  • cover exact reuse, every key component, per-compute lifetime, thrown-value identity, failure retry, and shared Native/WASI behavior

Root 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 a HashMap<MeasureCacheKey, Size<f32>>, so its entries are dropped automatically when that compute returns.

The key contains:

  • raw node ID
  • known width and height, including None versus exact f32::to_bits()
  • available width and height, distinguishing Definite(bits), MinContent, and MaxContent

The 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.

Package Before After Change
@taffyjs/node 44.2894 ms 18.1828 ms -58.9%
@taffyjs/wasm 356.2007 ms 133.2282 ms -62.6%

The 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 tests
  • vp 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 build
  • vp run benchmark --scenario=coding-agent-chat-initial-layout — three runs before and three runs after; medians reported above
  • vp run benchmark — complete local suite passed with equivalent layout validation
  • bounded independent adversarial review — PASS

Fixes #38

@hyfdev
hyfdev marked this pull request as ready for review August 17, 2026 14:09
Copilot AI lite review requested due to automatic review settings August 17, 2026 14:09
@hyfdev
hyfdev merged commit d73e335 into main Aug 17, 2026
7 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

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.

Cache identical measure requests within one layout pass

2 participants