food_chain/docs/performance-cost-audit/README.md
2026-09-29 23:45:12 +09:00

137 lines
9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Performance / Memory Cost Audit
## Purpose
Audit the integrated Mandelbrot viewer for processing that is low-value, redundant, or harmful from a speed / memory perspective. This audit intentionally **does not remove or alter any production behavior** in `index.html`.
Production source audited:
- `index.html`
- SHA-256: `544820c5024cf6d56e012db6d1bec3ddfcef5d833691b890baa64b26c5c2ee5a`
- Regression: PASS, 19 WGSL kernels
Measurements are CPU/static surrogates unless explicitly stated. Real WebGPU frame timing is not available in this container because the browser WebGPU backend cannot initialize successfully here.
## Conclusions
### A — High-confidence waste / harmful cost
| ID | Finding | Cost | Benefit observed | Confidence |
|---|---|---|---|---|
| A1 | Numeric history is recopied after every accepted recolor | 8 B/px copy per recolor | Numeric data did not change | Very high |
| A2 | `cpuFrameRgba` retains the assembled CPU fallback frame but is never read | 4 B/px JS heap retained | None | Very high |
| A3 | `certifyInterior()` runs a full-frame unknown-statistics pass and waits for GPU completion before primary compute | Full meta scan + queue synchronization | Partial proof/history-seed caller does not consume these stats | Very high |
| A4 | Strict direct rendering still updates Brent-cycle state even though periodicity classification is disabled | Per-iteration ALU/register state | None in strict mode | Very high |
| A5 | Export workspace survives export completion | Up to ~24 MiB GPU memory with 512 tiles / 3 slots | None while not exporting | Very high |
| A6 | Deep active/correction workspaces survive the hard frame that required them | active workspace up to ~44.1 MiB standard / ~176.5 MiB high; dense correction queue 4/16 MiB | None on later easy frames until reuse/resize | High |
### B — Strong optimization candidates, but keep until GPU A/B validation
| ID | Finding | Evidence | Assessment |
|---|---|---|---|
| B1 | Numeric history is always resident although exact-grid pan reuse is restrictive | 8 B/px resident. Under common budget-scaled resolutions, integer CSS pans 1–100 px produced 0/100 exact-grid reuse hits in the static alignment test | Likely over-allocated; make lazy/telemetry-driven rather than delete immediately |
| B2 | CPU exact cardioid/bulb tile proof runs for every numerical frame | 1024×768: ~4.8–6.1 ms median; 2048²: ~25–28 ms median. Four of six fixed corpus views certified 0 pixels | Add cheap spatial gate; direct backend especially needs A/B comparison |
| B3 | `fast-coverage-repair` runs a full-screen FAST pass after tiled coverage | Tile loops cover the full compute domain; mode 2 only repairs reason=0 untouched metadata | Likely redundant defensive pass; instrument reason=0 count before removal |
| B4 | `captureColorSource()` snapshots `meta+smooth` during rendering | 8 B/px copy per snapshot; provisional snapshots can occur every 125 ms. Snapshot allocation is 12 B/px | Useful only for live recoloring while render is in flight; gate more aggressively |
| B5 | Color-auto idle mode retains a color snapshot | standard ~12 MiB, high ~48 MiB at preset caps | Idle color-auto recolor path uses current field, not `recolorPublished()` | Snapshot should be render-only/on-demand |
| B6 | Adaptive initial-iteration probe uses high-precision scoring before every adaptive frame | Fixed corpus: ~1.3–12.5 ms and all six chose 350. Exploratory views can choose 512, so feature is not useless | Cache/gate/replace with cheaper trigger; do not delete blindly |
| B7 | Active continuation can replay already-performed iterations | initial OP_LIMIT session starts state at n=0; reference change resets progress to 0; recovered pixels can rebuild whole active session | Potentially large on the hardest views; add replay counters before redesign |
### C — Expensive but currently justified / not a deletion target
- General periodicity detection: CPU surrogate showed ~98% iteration reduction in period-3 interiors. It can add overhead on boundary-only views, but removal is not justified.
- Sparse numerical correction and reason bucketing: it adds full scans/queue construction, but isolates expensive DS/BigInt work. Needs GPU A/B before structural change.
- Stable texture reprojection: consumes one history texture but directly improves interaction latency.
- Reference cache / guided multi-reference: memory cost is bounded and prior evaluation showed reduced perturbation mismatch.
- Series approximation: small reference metadata cost with large deep-zoom iteration skip in prior evaluation.
## Key measurements
### Recolor numeric-history copy bandwidth
`commitHistory()` always calls `commitNumericHistory()`. Therefore a color-only update copies unchanged `meta` and `smooth` buffers (8 B/px). Color auto can request a pass every 50 ms while idle.
| preset cap | unchanged numeric copy / recolor | at 20 Hz |
|---|---:|---:|
| fast, 524,288 px | 4 MiB | 80 MiB/s |
| standard, 1,048,576 px | 8 MiB | 160 MiB/s |
| high, 4,194,304 px | 32 MiB | 640 MiB/s |
This is in addition to the actual color pass bandwidth.
### Color snapshot
`captureColorSource()` allocates/copies:
- meta: 4 B/px
- smooth: 4 B/px
- texture: 4 B/px
Resident cost = 12 B/px: ~6 MiB fast, 12 MiB standard, 48 MiB high at preset caps. A provisional snapshot copies 8 B/px and can be refreshed at up to 8 Hz, equivalent to ~32 / 64 / 256 MiB/s at the preset caps.
### Exact interior tile proof
Seven-run median on this host:
| view | 1024×768 | certified | 2048×2048 | certified |
|---|---:|---:|---:|---:|
| overview | ~6.1 ms | 7.3% | ~25.5 ms | 8.6% |
| period3 bulb | ~5.1 ms | 0% | ~26.5 ms | 0% |
| period3 core | ~4.8 ms | 0% | ~28.1 ms | 0% |
| seahorse boundary | ~6.0 ms | 0% | ~25.1 ms | 0% |
| seahorse deep | ~5.6 ms | 0% | ~26.1 ms | 0% |
The exact proof is still useful in views that overlap the main cardioid / period-2 bulb, especially on the perturbation path. The issue is unconditional invocation, not the proof mechanism itself.
### Exact-grid numeric-history reuse
The history seed requires identical span and an approximately integer render-pixel shift. When the resolution is pixel-budget limited, render pixels often do not align with CSS pixels.
Examples from the current resize rule, testing integer CSS horizontal pans of 1–100 px:
| screen / quality | render size | reuse hits |
|---|---:|---:|
| 1920×1080 / fast | 965×543 | 0/100 |
| 1920×1080 / standard | 1365×768 | 0/100 |
| 1920×1080 / high | 2731×1536 | 0/100 |
| 1024×768@1× / standard | 1024×768 | 100/100 |
This is a static alignment test, not real interaction telemetry. It supports making numeric history conditional rather than proving that it has no value.
### Persistent workspaces
- Sparse active workspace, worst full-active capacity: ~44.1 MiB standard, ~176.5 MiB high.
- At 10% active: ~5.64 MiB standard, ~22.51 MiB high.
- Dense deep correction queue: 4 MiB standard, 16 MiB high.
- Export workspace at 512 tile, depth 3: ~24 MiB retained after export.
- Non-AA export currently allocates four 512² sample textures, ~4 MiB per slot, although 1× rendering does not need the four AA sample textures.
## Static code locations
- `index.html:1299-1300`: pre-primary unknown stats + synchronization in `certifyInterior()`.
- `index.html:1383-1384`: full numeric-history copy.
- `index.html:1416`: `commitHistory()` always commits numeric history.
- `index.html:1822`: color-only recolor promotes history and therefore triggers numeric copy.
- `index.html:1718`: `state.cpuFrameRgba=rgba`; the state value has no reader.
- `index.html:162-163`: cycle state still updated in strict direct mode.
- `index.html:1349-1350`: tiled FAST coverage followed by full-screen coverage-repair pass.
- `index.html:1751-1756`: provisional color snapshots at 125 ms throttle.
- `index.html:1774`: old completed field snapshot at every numerical render start.
- `index.html:1866`: idle color-auto snapshot allocation.
- `index.html:1218`: active workspace persists unless another active allocation request causes a >4× shrink.
- `index.html:1217`: full-pixel dense correction queue persists once allocated.
- `index.html:1222-1226, 1898-1944`: export workspace lifetime extends beyond export job.
- `index.html:1306-1307, 1648, 1654`: active continuation reinitialization/rebuild can reset progress.
## Recommended instrumentation before deleting anything
1. Add counters for numeric-history `attempt / hit / reused pixels / bytes copied`.
2. Count reason-0 pixels immediately before `fast-coverage-repair`; if consistently zero, remove/disable that pass in an A/B branch.
3. Record `certifiedInteriorTiles` CPU ms and certified ratio per frame; gate when hit rate stays zero.
4. Record active-continuation `reinitCount` and `replayedPixelIterations`.
5. Record peak/resident bytes for active, correction, export, color snapshot and release-on-idle experiments.
6. Separate color-history promotion from numeric-history promotion and A/B color-auto frame time.
## Production integrity
No production deletion or behavioral modification was made by this audit. Regression was rerun after inspection and passed.