Skip to content

perf(cg): skip prefill loop on cache-warm frames via generation tracking#618

Merged
softmarshmallow merged 14 commits intocanaryfrom
feature/stupefied-mendeleev
Mar 31, 2026
Merged

perf(cg): skip prefill loop on cache-warm frames via generation tracking#618
softmarshmallow merged 14 commits intocanaryfrom
feature/stupefied-mendeleev

Conversation

@softmarshmallow
Copy link
Copy Markdown
Member

@softmarshmallow softmarshmallow commented Mar 31, 2026

Add a monotonically increasing generation counter to PictureCache that increments on any mutation (insert, invalidate). The prefill loop now compares the current generation, variant key, and layer count against the last successful prefill — when all match, the entire O(N) iteration is skipped in O(1).

On 135K-node scenes, this eliminates ~800µs of HashMap lookups per cache-warm frame. Measured improvements on 01-135k.perf.grida:

  • rt_pan_fast_fit p50: 111µs → 76µs (-32%)
  • rt_pan_fast_fit p95: 263µs → 153µs (-42%)
  • pan_settle_slow_fit settle: 1034µs → 709µs (-31%)
  • Criterion large_baseline/pan: -14.0% (p < 0.01)

Summary by CodeRabbit

  • Refactor

    • Improved rendering performance with optimized scene caching that reduces unnecessary processing when scenes remain unchanged.
  • Documentation

    • Added documentation describing cache validation optimization techniques and performance benefits for scene rendering.

softmarshmallow and others added 13 commits March 29, 2026 19:32
…y fixtures

Removed all 12 original fixtures that relied on unsupported CSS features
(grid, margin, tables, viewport units). Added 21 new fixtures organized
by category (layout, box, paint, text, mixed), each testing a specific
CSS property group using only features the HTML→IR pipeline supports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add csscascade adapter, cascade driver, and arena DOM modules
- Add HTML import module (html/mod.rs) with Stylo-based CSS resolution
- Wire grida-dev to load .html files via from_html_str
- Support ~35 CSS properties: layout (flex, block, display:none),
  box model (width/height/min/max/padding/overflow), paint (backgrounds,
  gradients, borders, shadows, opacity), text (font, color, align,
  line-height, letter-spacing, word-spacing, text-transform, decoration),
  and inline style attributes
- Map block containers to flex-column for correct flex-child sizing
- Emit text-only elements as Container+TextSpan to preserve box model

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Keep HTML import pipeline additions alongside main's raster image
refactoring (load_raster/RasterScene). Remove duplicate pub mod query.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The CSS cascade adapter uses a process-global DEMO_DOM static, so
concurrent from_html_str calls race on that shared slot causing Stylo
debug_assert panics. Added a mutex to serialize HTML tests. Also ran
cargo fmt to fix formatting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace css_box_shadow_to_cg with comprehensive css_effects_to_cg
  handling box-shadow, filter: blur(), filter: drop-shadow(), and
  backdrop-filter: blur() in a single pass
- Add css_text_shadow_to_effects for text-shadow on TextSpan nodes
- Add css_blend_mode_to_cg mapping all 16 CSS mix-blend-mode values
- Wire effects + blend_mode into all three emitters (container, rect, text)
- Fix test mutex poisoning cascade with lock_html() helper
- Add 8 deterministic tests for effects properties

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire text-decoration-color and text-decoration-style from Stylo into
TextDecorationRec. Mark thickness and skip-ink as TODO (gecko-only in
Stylo servo mode). Add L0 fixtures for text-decoration variants and
2D CSS transforms (implementation pending).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add docs/wg/format/ with canonical tracking docs for the Grida IR
schema and its mapping from CSS, HTML, and SVG. Tables are oxfmt-
formatted to minimize diffs on future edits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add docs/wg/format/index.md as docusaurus entry point. Add format:md
frontmatter to grida.md, css.md, svg.md for MDX compatibility. Link
format mapping docs from format/README.md, format/AGENTS.md, and
docs/AGENTS.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove CSS_PROPERTY_MAPPING.md (aspirational, marked unimplemented
features as done) and html/TODO.md (superseded by docs/wg/format/).
Update csscascade README roadmap to reflect current state. Add doc
pointer in html/mod.rs to the canonical tracking docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove dead no-op code (is_none → assign None) in emit_container
- Remove unconditional eprintln in from_html_str (library code)
- Add thread safety warning to from_html_str doc comment
- Document text-decoration single-line limitation with TODO
- Fix index.md missing format:md frontmatter
- Fix svg.md stroke table missing Notes header column
- Fix fixture title claiming "Thickness" coverage
- Remove text-shadow/text-transform from README excluded list

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: HTML/CSS → Grida IR import pipeline
Add a monotonically increasing generation counter to PictureCache that
increments on any mutation (insert, invalidate). The prefill loop now
compares the current generation, variant key, and layer count against
the last successful prefill — when all match, the entire O(N) iteration
is skipped in O(1).

On 135K-node scenes, this eliminates ~800µs of HashMap lookups per
cache-warm frame. Measured improvements on 01-135k.perf.grida:
- rt_pan_fast_fit p50: 111µs → 76µs (-32%)
- rt_pan_fast_fit p95: 263µs → 153µs (-42%)
- pan_settle_slow_fit settle: 1034µs → 709µs (-31%)
- Criterion large_baseline/pan: -14.0% (p < 0.01)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@softmarshmallow softmarshmallow changed the base branch from main to canary March 31, 2026 16:41
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Mar 31, 2026 5:53pm
6 Skipped Deployments
Project Deployment Actions Updated (UTC)
code Ignored Ignored Mar 31, 2026 5:53pm
legacy Ignored Ignored Mar 31, 2026 5:53pm
backgrounds Skipped Skipped Mar 31, 2026 5:53pm
blog Skipped Skipped Mar 31, 2026 5:53pm
grida Skipped Skipped Mar 31, 2026 5:53pm
viewer Skipped Skipped Mar 31, 2026 5:53pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 44af7f27-859c-466e-b36f-69cef2ca729c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

The PR adds a generation-based cache invalidation optimization to skip redundant picture cache prefill operations. A monotonic counter in PictureCache increments on mutations; Renderer records the generation plus metadata (variant key and layer count) after prefill, then skips the O(N) iteration on subsequent frames if all three values remain unchanged.

Changes

Cohort / File(s) Summary
Picture Cache Mutation Tracking
crates/grida-canvas/src/cache/picture.rs
Added generation: u64 field and public generation() accessor. Cache mutations (set_node_picture, set_node_picture_variant, invalidate, invalidate_node) now increment generation using wrapping_add(1). Added variant_store_is_empty() helper. Restructured set_node_picture_variant control flow to ensure consistent generation increments across all insert paths.
Prefill Skip Optimization
crates/grida-canvas/src/runtime/scene.rs
Added three tracking fields to Renderer: last_prefill_generation, last_prefill_variant_key, and last_prefill_layer_count. In prefill_picture_cache_for_plan, a new fast-path computes effective variant key and visible layer count; if all three tracking values match current cache state, prefill iteration is skipped. Tracking fields updated after successful prefill and initialized to sentinel values (u64::MAX/u64::MAX/0).
Optimization Documentation
docs/wg/feat-2d/optimization.md
Added new section describing the "Picture Cache Prefill Skip" mechanism, explaining generation counter semantics, variant key unification for effect-free scenes, skip-path correctness across stable/unstable transitions, and performance deltas.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

cg, performance

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main optimization: skipping the prefill loop on cache-warm frames using generation tracking.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/stupefied-mendeleev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ddb8f6f89

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +420 to +423
if current_gen == self.last_prefill_generation
&& effective_key_for_tracking == self.last_prefill_variant_key
&& layer_count == self.last_prefill_layer_count
{
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Include visible-set identity in prefill skip key

The new fast-path returns early when generation, variant_key, and only the count of planned layers match, but panning can change which nodes are visible while keeping the same count. In that case this check skips prefill_picture_cache_for_plan() even though newly visible nodes are not cached yet; since prefill is the only path that inserts node pictures, those nodes can remain uncached across frames (same generation/count), causing sustained cache misses and a performance regression during viewport movement.

Useful? React with 👍 / 👎.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel vercel bot temporarily deployed to Preview – blog March 31, 2026 17:52 Inactive
@vercel vercel bot temporarily deployed to Preview – viewer March 31, 2026 17:52 Inactive
@vercel vercel bot temporarily deployed to Preview – backgrounds March 31, 2026 17:52 Inactive
@vercel vercel bot temporarily deployed to Preview – grida March 31, 2026 17:52 Inactive
@softmarshmallow softmarshmallow merged commit 855e48c into canary Mar 31, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant