Files
hcie-rust-v3.05/.kilo/plans/1784909963922-criterion-move-and-optimize.md
T
Your Name 8563a44211
mandatory-regression-gate / deterministic-tests (push) Has been cancelled
mandatory-regression-gate / protected-performance-path (push) Has been cancelled
Add SVG report for typical stroke mask pooling at warm 10th stroke
2026-07-24 23:43:42 +03:00

7.5 KiB
Raw Blame History

Plan: Relocate Criterion Results + Optimize to 2× gold_standard

Context

Criterion benchmarks exist under target/criterion/ with gold-standard baselines already saved. The criterion-test branch introduced benchmarks; the current performance-optimization branch added bench = false and reverted blend_mode.

Current gold_standard timings (mean):

Benchmark ns (mean) ~seconds
below_cache_reuse/first_stroke_cache_build 807,729,115 0.81 s
below_cache_reuse/second_stroke_cache_reuse 14,573,274 0.015 s
composite_scratch_pooling/cold_composite 1,048,196,885 1.05 s
composite_scratch_pooling/warm_composite 10,073,839 0.010 s
effects_skip/no_effects_composite 14,340,411 0.014 s
effects_skip/with_one_dropshadow 14,780,582 0.015 s
stroke_mask_pooling/cold_first_stroke 46,427,571 0.046 s
stroke_mask_pooling/warm_10th_stroke 16,749,902 0.017 s

Dominant costs: first_stroke_cache_build (0.81 s) and cold_composite (1.05 s).

Target: 2× faster on cold/first-stroke paths; zero regressions on warm paths.


Phase 1 — Relocate target/criterion to project root

1.1: Move the results directory

mv target/criterion ./criterion

1.2: Update .gitignore

Add !/criterion exception. The current rule /target/ won't affect root-level criterion/ but /target/ plus **/target/ should be reviewed. Actually /target/ only matches the root target/ dir, and **/target/ matches nested ones, so criterion/ at root is fine. No .gitignore change needed.

1.3: Configure criterion output directory

Criterion 0.5 uses CRITERION_HOME env var (defaults to target/criterion). After move, either:

Option A (preferred): Set CRITERION_HOME via .cargo/config.toml:

[env]
CRITERION_HOME = "criterion"

Option B: Export before benching:

CRITERION_HOME=criterion cargo bench -p hcie-engine-api

1.4: Update criterion.md

Replace ./target/criterion/report/index.html./criterion/report/index.html.

1.5: Update notlar.txt

Update the bench command section to reflect CRITERION_HOME=criterion usage.


Phase 2 — Fix benchmark correctness

2.1: Remove bench = false from hcie-engine-api/Cargo.toml

Line 37: bench = false must be removed for [[bench]] targets to work correctly. This was a workaround from commit ee6ad2d.

2.2: Verify effects_skip.rs blend_mode

Current "Normal".to_string() matches LayerStyle::DropShadow { blend_mode: String } — correct. The criterion-test branch had hcie_engine_api::BlendMode::Normal which is a type mismatch. No change needed.


Phase 3 — Optimization loop targeting 2× on cold paths

Prerequisite: Engine crates are locked (chmod 444). Use ./unlock.sh <crate> to modify, ./lock.sh <crate> after.

3.0: Save current state as gold_standard baseline

cargo bench -p hcie-engine-api -- --save-baseline gold_standard

3.1: Optimize below_cache construction (first_stroke_cache_build: 0.81 s → ≤0.40 s)

Unlock: ./unlock.sh hcie-engine-api File: hcie-engine-api/src/stroke_cache.rs:513-608rebuild_below_cache_if_needed()

The function calls tiled::composite_tiled_into() for the full canvas (3840×2160). Optimization candidates:

  1. Parallelize the below-cache tile build loop (line 547-561). Currently iterates layers sequentially to build tiles. Use par_iter for tile construction.

  2. Skip fully invisible layers in below-cache. Check tl.visible before compositing.

  3. Pre-fill with topmost opaque Normal-blend layer. Walk bottom→top, find the first fully opaque Normal-blend layer, fill everything below it at once.

  4. Reduce zero-fill cost. The 33 MB cache.fill(0) at line 564 is sequential. Consider unsafe { std::ptr::write_bytes } for SIMD-accelerated zeroing.

Lock: ./lock.sh hcie-engine-api

3.2: Optimize cold composite (cold_composite: 1.05 s → ≤0.52 s)

Unlock: ./unlock.sh hcie-engine-api File: hcie-engine-api/src/partial_composite.rs:90-228render_composite_region() cold path (lines 194-222)

The cold path zeroes the scratch buffer then composites all layers. Optimization candidates:

  1. Parallel scratch buffer zeroing. Replace row-by-row buf[start..end].fill(0) with par_chunks_exact_mut.

  2. Merge zero-fill with first-layer composite. Instead of fill(0) then composite, start the first layer's composite directly (it overwrites anyway if using Normal blend).

  3. Skip tile sync for unchanged layers. In apply_effects_and_sync_tiles(), the sync_dirty_tiles() re-tiles every dirty layer even if pixels haven't changed since last sync.

  4. Cache the tile compositing results. If the same layer stack was composited before, reuse intermediate results.

Lock: ./lock.sh hcie-engine-api

3.3: Optimize tiled compositing inner loop

Unlock: ./unlock.sh hcie-composite File: hcie-composite/src/tiled.rs

The composite_tiled_into() function handles small-region vs full-canvas compositing. The AGENTS.md note says small regions use sequential, large regions use par_chunks_exact_mut. Verify the full-canvas path (below-cache build and cold composite) actually uses parallel compositing.

Optimization candidates:

  1. Ensure par_chunks_exact_mut is used for full-canvas compositing in tiled.rs.
  2. Reduce per-tile overhead. Check if tile lookups, bounds checks, or branching in the hot loop can be eliminated.

Lock: ./lock.sh hcie-composite

3.4: Validate after each optimization

After EACH change:

# Pixel-perfect correctness (MUST pass)
cargo test -p hcie-engine-api --test visual_regression

# Regression check vs gold_standard (MUST show improvement, no regressions)
cargo bench -p hcie-engine-api -- --baseline gold_standard

# Performance regression test
cargo test -p hcie-engine-api --test performance_stroke_4k -- --nocapture

3.5: Re-save gold_standard after achieving target

cargo bench -p hcie-engine-api -- --save-baseline gold_standard

Phase 4 — Re-lock all engine crates

./lock.sh hcie-engine-api
./lock.sh hcie-composite

Files Modified

File Change
target/criterion/./criterion/ Directory move
.cargo/config.toml Add CRITERION_HOME = "criterion"
criterion.md Update output path
notlar.txt Update bench instructions
hcie-engine-api/Cargo.toml Remove bench = false
hcie-engine-api/src/stroke_cache.rs below_cache optimization
hcie-engine-api/src/partial_composite.rs Cold composite optimization
hcie-composite/src/tiled.rs Tiled compositing optimization

Risks

Risk Mitigation
CRITERION_HOME doesn't work with criterion 0.5 Fallback: use --output-dir criterion flag or .cargo/config.toml [env] section
Engine optimizations break pixel-perfect rendering Run visual_regression test after every change
Changes to hot path break AGENTS.md-protected mechanisms Verify all protected mechanisms still pass; no changes to pooling logic correctness
2× target not achievable with these optimizations Profile further; consider SIMD, parallelism in deeper layers

Validation Commands

cargo bench -p hcie-engine-api -- --baseline gold_standard
cargo test -p hcie-engine-api --test visual_regression
cargo test -p hcie-engine-api --test performance_stroke_4k -- --nocapture
cargo bench -p hcie-engine-api --no-run