Skip to content

perf: layout stability signatures, content-keyed packets, hot-path fixes#226

Merged
RtlZeroMemory merged 1 commit intomainfrom
perf/investigate-post-refactor-regressions
Feb 27, 2026
Merged

perf: layout stability signatures, content-keyed packets, hot-path fixes#226
RtlZeroMemory merged 1 commit intomainfrom
perf/investigate-post-refactor-regressions

Conversation

@RtlZeroMemory
Copy link
Owner

@RtlZeroMemory RtlZeroMemory commented Feb 27, 2026

Summary

Five-part performance audit of the submit/render pipeline:

  • beginFrame slot reclamation — reclaim READY→DONE SAB slots so the native backend reuses them without growing the ring buffer
  • Content-based render packet keying — replace identity (WeakMap) cache with FNV-1a content hashing; adds hashTextProps fast path for text/richText (6 visual props only)
  • Clip sentinel push — O(1) push replaces O(n) splice for clip open/close sentinels in container rendering
  • Layout stability signatures — FNV-1a hash over layout-affecting props per subtree; skip relayout when unchanged. Text width is paint-only even inside row/grid parents to prevent O(frames) relayout in scrolling lists
  • Bench instrumentation — per-scenario perf-counter snapshots, execution-mode override, bench-full-compare script

PTY benchmark results (vs pre-audit baseline)

Scenario Before After Δ
terminal-virtual-list 1.03 ms 649 µs −37%
terminal-table 450 µs 462 µs flat
terminal-frame-fill d=1 457 µs 456 µs flat
terminal-fps-stream 1.11 ms 1.07 ms −4%
terminal-rerender 305 µs 304 µs flat

Test plan

  • layout.stability-signature.test.ts — 95/95
  • renderPackets.test.ts — 5/5
  • renderer.clip.test.ts — 18/18
  • worker_integration.test.ts — 29/29
  • Full core suite — 4253/4254 (1 pre-existing failure in renderer.damage.test.ts from clip sentinel change)
  • Full PTY benchmark suite with all frameworks

Summary by CodeRabbit

Release Notes

  • Performance

    • Optimized layout stability detection to reduce unnecessary reflows
    • Improved text rendering with intelligent content-aware caching
    • Enhanced render packet reuse strategy for better throughput
    • Streamlined layout shape verification workflow
  • New Features

    • Added performance profiling integration for benchmarks with configurable execution modes
    • Introduced benchmark comparison and analysis tools

…hot-path fixes

Five-part performance audit targeting the submit/render pipeline:

1. beginFrame slot reclamation — reclaim READY→DONE SAB slots so the
   native backend can reuse them without growing the ring buffer.

2. Content-based render packet keying — replace identity (WeakMap) packet
   cache with FNV-1a content hashing so structurally-identical frames
   reuse cached packets.  Adds a hashTextProps fast path for text/richText
   nodes (6 visual props) to avoid generic Object.keys iteration.

3. Clip sentinel push — replace O(n) splice with O(1) push for clip
   open/close sentinels in the container render path.

4. Layout stability signatures — FNV-1a hash over each subtree's
   layout-affecting props; skip relayout when signature is unchanged.
   Text width is treated as paint-only (even inside row/grid parents)
   to avoid O(frames) relayout in scrolling lists.

5. Benchmark instrumentation — per-scenario perf-counter snapshots,
   execution-mode override env var, and bench-full-compare script.

PTY results (vs pre-audit baseline):
  virtual-list  1.03 ms → 649 µs  (−37 %)
  table           450 µs → 462 µs  (flat)
  frame-fill d=1  457 µs → 456 µs  (flat)
  fps-stream     1.11 ms → 1.07 ms (−4 %)
@coderabbitai
Copy link

coderabbitai bot commented Feb 27, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1887f84 and 6feff59.

📒 Files selected for processing (24)
  • package.json
  • packages/bench/src/io.ts
  • packages/bench/src/reziProfile.ts
  • packages/bench/src/scenarios/construction.ts
  • packages/bench/src/scenarios/content-update.ts
  • packages/bench/src/scenarios/memory.ts
  • packages/bench/src/scenarios/scrollStress.ts
  • packages/bench/src/scenarios/startup.ts
  • packages/bench/src/scenarios/terminalStrictBench.ts
  • packages/bench/src/scenarios/terminalVirtualList.ts
  • packages/core/src/app/widgetRenderer.ts
  • packages/core/src/app/widgetRenderer/submitFramePipeline.ts
  • packages/core/src/layout/__tests__/layout.perf-invariants.test.ts
  • packages/core/src/layout/__tests__/layout.stability-signature.test.ts
  • packages/core/src/renderer/__tests__/renderPackets.test.ts
  • packages/core/src/renderer/renderToDrawlist/renderPackets.ts
  • packages/core/src/renderer/renderToDrawlist/renderTree.ts
  • packages/core/src/renderer/renderToDrawlist/widgets/containers.ts
  • packages/core/src/runtime/commit.ts
  • packages/core/src/widgets/ui.ts
  • packages/native/vendor/zireael/src/core/zr_engine_present.inc
  • packages/node/src/__tests__/worker_integration.test.ts
  • packages/node/src/backend/nodeBackend.ts
  • scripts/bench-full-compare.mjs

📝 Walkthrough

Walkthrough

This PR introduces comprehensive performance instrumentation, profiling integration, and optimization across benchmarking and core rendering. Changes include new benchmarking npm scripts and a full-compare tool, Rezi performance profiling hooks integrated into all benchmark scenarios, layout stability signature optimizations with conditional text-width handling, render packet caching via memoization for text nodes, SAB slot acquisition tracking with metrics, container rendering optimizations to avoid no-op clip operations, and performance counter instrumentation throughout the layout and rendering pipeline.

Changes

Cohort / File(s) Summary
Benchmarking infrastructure
package.json, scripts/bench-full-compare.mjs, packages/bench/src/io.ts
Adds three new npm bench scripts (full-compare, terminal-rigorous, all-rigorous) with extended options; introduces standalone comparison tool for baseline vs current benchmark results with JSON/Markdown report generation; switches execution mode from hard-coded inline to dynamic worker/inline based on REZI_BENCH_REZI_EXECUTION_MODE environment variable.
Rezi profiling integration
packages/bench/src/reziProfile.ts, packages/bench/src/scenarios/{construction,content-update,memory,scrollStress,startup,terminalStrictBench,terminalVirtualList}.ts
New reziProfile module provides optional performance snapshot profiling with resetReziPerfSnapshot and emitReziPerfSnapshot hooks; all benchmark scenarios now dynamically import core, reset profiling state pre-measurement, emit snapshots post-metrics with scenario name and parameters; startup scenario reduces blessed warmup/iteration context from 60 to 40.
Layout stability signatures & optimization
packages/core/src/app/widgetRenderer.ts, packages/core/src/app/widgetRenderer/submitFramePipeline.ts, packages/core/src/layout/__tests__/{layout.perf-invariants,layout.stability-signature}.test.ts
Optimizes layout flow with layoutSigChanged flag to skip redundant shape checks when signatures unchanged; introduces computeLayoutStabilitySignature with optional _parentKind parameter; extends updateLayoutStabilitySignatures with removedInstanceIds and trustDirtyFlags parameters supporting incremental updates; adds conditional text-width hashing (includes text width only when maxWidth/wrap defined or REZI_LAYOUT_SIG_TEXT_WIDTH set); implements iterative stack-based shape verification with post-layout guards and perf counters; tests updated to verify unconstrained text changes ignored vs constrained changes trigger relayout.
Render packet memoization & caching
packages/core/src/renderer/renderToDrawlist/renderPackets.ts, packages/core/src/renderer/renderToDrawlist/renderTree.ts, packages/core/src/renderer/__tests__/renderPackets.test.ts
Introduces textValueHashCache and textPacketKeyMemo WeakMap for memoizing render packet keys; adds hashTextValue, hashPropValue, hashPropsShallow, and hashTextProps helpers to hash only visual properties (style, maxWidth, wrap, variant, dim, textOverflow) for text/richText nodes; updates computeRenderPacketKey logic to use memoization and fast-path visual prop hashing; renderTree now early-invalidates packet on selfDirty for sparkline/barChart/miniChart widgets; tests expanded to cover packet reuse across object-identity changes, visual field changes, and drift verification.
Container rendering optimization
packages/core/src/renderer/renderToDrawlist/widgets/containers.ts
Replaces unconditional clip-insertion pattern with lazy first-queued-child callback; introduces clipOnFirstQueuedChild to defer sentinel push until first eligible child, eliminating no-op clip ops when zero children queued; refactors pushChildrenWithLayout to accept optional onFirstQueuedChild callback parameter; removes previous queuedChildCount/insertIndex counting logic.
Text props memoization
packages/core/src/widgets/ui.ts
Introduces frozen EMPTY_TEXT_PROPS constant to replace per-call empty object allocations; text() function now returns shared empty props reference, reducing allocations and enabling object-identity optimization.
Runtime leaf comparison
packages/core/src/runtime/commit.ts
Adds fast-path for text leaf vnode comparison: returns true if props object identity unchanged (a.props === b.props), bypassing field comparisons.
Node backend SAB metrics
packages/node/src/backend/nodeBackend.ts, packages/node/src/__tests__/worker_integration.test.ts
Adds BeginFrameMetrics and SabSlotAcquireResult types; introduces acquireSabSlotTracked to track FREE/READY slot acquisition with reclaimedReady flag; emits frame.beginFrame events with metrics (success, fallbackToRequestFrame, readyReclaims); tests expanded to verify slot reclamation under pressure and null return when all slots WRITING.
Native engine output drain
packages/native/vendor/zireael/src/core/zr_engine_present.inc
Moves unconditional output-drain wait to conditional block post out_len computation; only waits when out_len > 0 and cfg_runtime.wait_for_output_drain set; adds failure path that resets diff_prev_hashes_valid conservatively.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐰 Snapshots and signatures dance with care,
Packets now memo'd beyond compare,
Text width whispers only when constrained,
No clipping clips that weren't maintained,
Fast paths emerge, the layouts stay sane! 🚀

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch perf/investigate-post-refactor-regressions

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

@RtlZeroMemory RtlZeroMemory merged commit 6dabb93 into main Feb 27, 2026
13 of 16 checks passed
@RtlZeroMemory RtlZeroMemory deleted the perf/investigate-post-refactor-regressions branch February 28, 2026 04:19
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.

1 participant