7.5 KiB
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-608 → rebuild_below_cache_if_needed()
The function calls tiled::composite_tiled_into() for the full canvas (3840×2160). Optimization candidates:
-
Parallelize the below-cache tile build loop (line 547-561). Currently iterates layers sequentially to build tiles. Use
par_iterfor tile construction. -
Skip fully invisible layers in below-cache. Check
tl.visiblebefore compositing. -
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.
-
Reduce zero-fill cost. The 33 MB
cache.fill(0)at line 564 is sequential. Considerunsafe { 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-228 → render_composite_region() cold path (lines 194-222)
The cold path zeroes the scratch buffer then composites all layers. Optimization candidates:
-
Parallel scratch buffer zeroing. Replace row-by-row
buf[start..end].fill(0)withpar_chunks_exact_mut. -
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).
-
Skip tile sync for unchanged layers. In
apply_effects_and_sync_tiles(), thesync_dirty_tiles()re-tiles every dirty layer even if pixels haven't changed since last sync. -
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:
- Ensure
par_chunks_exact_mutis used for full-canvas compositing in tiled.rs. - 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