# Performance profiling workflow

RUIN performance investigations should start with reproducible reports before
deep profiler sessions. The first-pass tooling is intentionally headless and
focused on high-signal app-build, layout, text, scene, and cache counters.

## Run a scenario

Use the `ruin_perf_scenarios` package in release mode:

```bash
cargo run -p ruin_perf_scenarios --release -- \
  --scenario large-scroll-list \
  --frames 300 \
  --output target/ruin-perf/large-scroll-list.json
```

List available scenarios:

```bash
cargo run -p ruin_perf_scenarios -- --list
```

Current scenarios:

| Scenario | What it stresses |
| --- | --- |
| `counter` | tiny reactive-style app tree rebuild and layout baseline |
| `large-scroll-list` | scroll culling, text cache reuse, layout cache behavior |
| `calculator` | realistic small app tree with display, button grid, and history |
| `resize-configure` | repeated viewport-size changes and layout reflow |
| `large-text-body` | huge wrapped text body, text layout cache behavior, scroll clipping |

The large text scenario accepts a body-size option:

```bash
cargo run -p ruin_perf_scenarios --release -- \
  --scenario large-text-body \
  --frames 100 \
  --text-kb 1024
```

Each run writes JSON under `target/ruin-perf/` by default and prints a compact
summary table to stdout.

## Interpreting the report

Start with the timing rows:

- `app_build`: time spent building the deterministic app tree for the frame.
- `layout_total`: full layout snapshot time.
- `layout_intrinsic`: intrinsic measurement work inside layout.
- `text_prepare` / `text_cache_miss`: text shaping/cache miss work.

Then inspect counters:

- High `layout_cache_misses` with low `layout_cache_hits` means the tree or
  layout constraints are changing in a way that defeats caching.
- High `viewport_culled` with low `scene_items` is expected for large scroll
  lists and means scene culling is working.
- High `text_cache_misses` or `text_cache_miss` time usually means text content,
  bounds, style, or cache keys are changing too much.
- Large `scene_items` or `text_glyphs` for tiny workloads suggests excessive UI
  tree expansion or missing culling.

## Investigation loop

1. Reproduce the suspected degenerate workload with the closest scenario.
2. Run it in release mode and keep the JSON report.
3. Compare the stdout summary with a known-good run or a smaller frame count.
4. If one phase dominates, use an OS profiler on that scenario:
   - macOS: Instruments Time Profiler / Allocations / Metal System Trace.
   - Linux: `perf`, `samply`, `heaptrack`, or RenderDoc as appropriate.
5. After identifying a concrete hot path, add or update a narrow Criterion
   benchmark before optimizing it.

## Validation

The scenario runner is part of the default workspace. The usual repository
validation should keep it healthy:

```bash
cargo test
cargo clippy --all-targets -- -D warnings
cargo clippy --release --all-targets -- -D warnings
```

## Current limitations

This first pass does not automate GUI input, GPU frame capture, or platform
presentation traces. Renderer frame counters are exposed for platform-backed
runs, but the headless scenario reports focus on app/layout/text degeneracy
first. Platform-backed resize/presentation report generation should be added
after these reports are useful enough to guide concrete optimization work.
