chore: extract PerfSampler from AutoPilot for AltTester reuse - #8826
Conversation
Move per-frame CPU/GPU sampling, CSV writer, 8-line summary writer, and PercentWorst out of AutoPilot.RunAsync into a new static PerfSampler (Configure/Begin/End). AutoPilot now brackets StandAtSpawnAsync with PerfSampler.Begin/End and keeps Application.Quit in finally. ProfilingPlugin calls PerfSampler.Configure(profiler) unconditionally, so AltTester-driven InWorld fixtures can drive Begin/End via AltDriver.CallStaticMethod without --autopilot. CSV columns, line endings (CRLF), encoding (UTF-8 no BOM), and the eight summary lines are byte-identical to the pre-refactor output.
|
Windows and Mac build successful in Unity Cloud! You can find a link to the downloadable artifact below. |
PercentWorst computed k as (int)(times.Count * fraction), which floors to 0 whenever Count * fraction < 1 — e.g. the 0.1% bucket on any window shorter than 1000 samples. Take(0).Average() then threw InvalidOperationException, killing the whole summary write. Standalone AutoPilot never hit this because StandAtSpawnAsync yields ~90s of samples on a dev machine. Fixture-level InWorld windows on the T4 chassis (~15-20s, low FPS) regularly land below 1000 samples and crashed the entire perf-summary writer. Floor k to 1 so 0.1% worst on small windows simply reports the worst single frame instead of crashing. Output is byte-identical for any window with >= 1000 samples (k = (int)(N * 0.001f) >= 1 already). Also guard the empty-list case defensively.
Bump cloud_build_url default to pr-22430-3a0b8d5, which carries the PerfSampler.PercentWorst guard against tiny sample windows (decentraland/unity-explorer#8826). Improve AttachPerf diagnostics: log ex.ToString() instead of just ex.Message so AltTester's wrapped TargetInvocationException reveals the real Player-side stack in the Allure report. Best-effort attach perf.csv on the End-failure path — PerfSampler.End disposes the CSV before WriteSummary runs, so a summary-side crash still leaves a complete CSV on disk that can be inspected post-mortem.
…lttester' into feat/test-automation/autopilot-alttester
This comment has been minimized.
This comment has been minimized.
|
PR #8826, run #26192309600 Builds: Windows change, Windows baseline, macOS change, macOS baseline Framework 13 i7
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
PR #8826, run #26217949913 Builds: Windows change, Windows baseline, macOS change, macOS baseline Framework 13 i7
|
pravusjif
left a comment
There was a problem hiding this comment.
If we extend some virtual input simulation for Alttester tests in the future, we can have automatized waypoint-based paths in-world, measuring performance thanks to this initiative, great job!
This comment has been minimized.
This comment has been minimized.
|
Claude finished @popuz's task in 1m 59s —— View job PR Re-review — chore: extract PerfSampler from AutoPilot for AltTester reuse
Root-cause checkThis PR extracts per-frame CPU/GPU sampling out of Progress since last review
Blocking IssueLINQ violation —
On the "it only runs in CI" argument: the code lives in REVIEW_RESULT: FAIL ❌ |
|
PR #8826, run #26233457658 Builds: Windows change, Windows baseline, macOS change, macOS baseline Framework 13 i7
|

What does this PR change?
Extracts per-frame CPU/GPU sampling out of
AutoPilotinto a reusablePerfSamplerso the same code path can produce perf summaries for both:--autopilot-csv/--autopilot-summaryCLI flow (byte-identical output).explorer-automation, which callPerfSampler.Begin/Endover the AltTester bridge to bracket a test fixture instead of a 90 sStandAtSpawnAsyncloop.Changes
PerformanceAndDiagnostics/AutoPilot/PerfSampler.cs—Configure(IProfiler)/Begin(csvPath, summaryPath)/End()static API. Owns the per-framePlayerLoophook, the CSV writer, the 8-line summary writer, and thePercentWorstaggregation. SameIProfiler.LastFrameTimeValueNs/LastGpuFrameTimeValueNssignal source as before — no newProfilerRecorderinstances, no analytics-pipeline dependency.AutoPilot.cs—RunAsyncnow bracketsStandAtSpawnAsync(90)withPerfSampler.Begin/End.Application.Quitstays infinallyand is only reachable from the standalone path; AltTester-driven sampling never quits the player.ProfilingPlugin.cs— callsPerfSampler.Configure(profiler)unconditionally (outside theAUTOPILOTflag gate) so the InWorld path works without--autopilot.Compatibility
CSV columns, line endings (CRLF), encoding (UTF-8 no BOM), and the eight summary lines (
CPU average,CPU 1% worst,CPU 0.1% worst,CPU worst,GPU average,GPU 1% worst,GPU 0.1% worst,GPU worst) are byte-identical to the pre-refactor output. The Part B consumer in explorer-automation parses the same file with one regex regardless of which path produced it.Test Instructions
Standalone path — same as before this PR:
Wait ~3 min (load + 90 s stand). Player exits.
perf-summary.txtshould contain the same 8 lines as a pre-refactor build.AltTester-driven path is exercised by the companion PR — no manual steps needed here:
Quality Checklist
--autopilot-summaryoutput verified byte-identical to pre-refactor.PerfSampler.Configureplacement reviewed — outside theAUTOPILOTgate so the InWorld path works.usingdirectives for analytics namespaces inPerfSampler.cs(signal source isIProfileronly).