acdream/docs/research/2026-07-24-performance-capture-playbook.md
Erik 3ee8ec537a perf(diag): complete trustworthy Slice A capture tooling
Correct whole-frame GPU timestamps so they bracket only the accepted render transaction and associate delayed query results with the owning CPU frame. Add route-wide frame-history summaries, fixed-camera screenshot comparison, process counters, contention traces, a pinned Arwic workload, and credential-safe launch disclosure.

The reference hardware/display contract now keeps local and RDP populations separate and defines the screenshot and re-baseline rules needed by later prepared-content gates.

Co-Authored-By: Codex <noreply@openai.com>
2026-07-24 12:46:51 +02:00

3.7 KiB

Performance capture playbook

This is the reproducible Slice A capture procedure for the Modern Runtime Architecture plan. The machine and graphical contract is 2026-07-24-performance-reference-configuration.json.

Connected captures

Build once from a clean tracked worktree:

dotnet build AcDream.slnx -c Release

Run the capped nine-stop route:

.\tools\run-connected-r6-soak.ps1 `
  -Repository (Get-Location).Path `
  -SkipBuild `
  -CaptureContention

Run the uncapped nine-stop route:

.\tools\run-connected-r6-soak.ps1 `
  -Repository (Get-Location).Path `
  -SkipBuild `
  -Uncapped

Run the pinned uncapped Arwic scene:

.\tools\run-connected-r6-soak.ps1 `
  -Repository (Get-Location).Path `
  -SkipBuild `
  -Uncapped `
  -DenseTown

Credentials come from ACDREAM_TEST_USER and ACDREAM_TEST_PASS, or the script's local test defaults. The generated environment disclosure redacts secret-like variable names. Never commit credentials, raw stdout/stderr, counter CSVs, .nettrace, or machine-local absolute paths.

Every run captures:

  • Per-frame CPU, GL GPU, frame-thread allocation, and stage history.
  • Route-wide and five-second checkpoint percentiles.
  • Per-portal windows from 10 seconds before through 5 seconds after materialization, including the 20 worst frames.
  • Process-wide System.Runtime counters at one-second cadence.
  • Canonical resource/checkpoint JSON and named screenshots.
  • Optional CLR contention events with call stacks.

-SkipRuntimeCounters exists for measurement-overhead experiments only. A baseline captured with it is incomplete.

Allocation and contention attribution

The per-frame history answers which frame and which update/upload phase was expensive. Canonical checkpoint deltas and runtime-counters.csv answer whether allocations were merely moved to workers.

For per-thread allocation stacks, make a separate reproduction capture so the observer cost is not mixed into the baseline:

dotnet-trace collect `
  --process-id <pid> `
  --providers Microsoft-Windows-DotNETRuntime:0x0000000000000001:5 `
  --duration 00:00:00:30 `
  --output allocation-stacks.nettrace

The provider enables CLR GC events at verbose level; inspect allocation-tick stacks grouped by managed thread in PerfView or Visual Studio. Interpret sampled bytes as attribution weights, not exact object sizes.

The soak's -CaptureContention mode captures the CLR contention keyword (0x4000) at verbose level. Inspect ContentionStart call stacks and group by lock acquisition site. The first comparisons are the DAT typed-object lock, ObjectMeshManager pending-request ownership, and any newly dominant caller; do not optimize a lock solely from event count.

Screenshot contract

Compare a candidate against the matching reference image:

dotnet .\src\AcDream.Cli\bin\Release\net10.0\AcDream.Cli.dll `
  compare-screenshots `
  <reference.png> `
  <candidate.png> `
  <comparison.json> `
  2 `
  0.001 `
  <optional-mask.png>

The routes pin world time and camera input. A nonzero-alpha mask excludes known dynamic pixels such as DAT particles. Never widen the global tolerance to conceal a deterministic geometry, texture, visibility, or UI difference.

Baseline authority

Name every committed compact result capped-local, uncapped-local, capped-rdp, or uncapped-rdp. RDP captures are diagnostic only for throughput. An authoritative local baseline must be run on the physical AMD display path defined in the reference configuration. A baseline report records the exact commit and must have a clean tracked source status.