game-perf-profiling
Profiles game builds against frame-time, memory, GPU draw-call, and GC-spike budgets using Unity Profiler + Profile Analyzer + Performance Testing package and Unreal Insights + stat commands. Establishes pass/fail thresholds (16.6 ms at 60 fps, 33.3 ms at 30 fps), writes automated performance regression tests that run in CI, and emits a structured budget report per SKU. Use when a title must hit a declared frame-time or memory budget before a milestone gate or platform-cert submission, or when a recent change needs a performance regression check.
Install with skills.sh (any agent)
npx skills add testland/qa --skill game-perf-profilinggame-perf-profiling
Overview
Game performance QA verifies that a build meets its declared budgets across every target SKU before milestone sign-off or platform-cert submission. The performance category (category 4 in the platform-cert-overview-reference test-category taxonomy) covers frame-time, memory, GPU, thermal, and battery axes. This skill covers the two dominant engine stacks: Unity and Unreal Engine.
Frame-time budget anchors (from platform-cert-overview-reference):
| Target frame rate | Frame-time budget |
|---|---|
| 60 fps | 16.67 ms per frame |
| 30 fps | 33.33 ms per frame |
Measuring averages is an anti-pattern: spikes hide in averages and cause cert failures. Measure p99 (99th-percentile frame time) and sustained-window maximums.
Step 1: Unity - Capture with the Profiler
Open the Profiler via Window > Analysis > Profiler (Ctrl+7) and enable the CPU Usage, GPU Usage, and Memory modules for a frame-time pass. Save the capture as a .data file (Profiler toolbar > Save) and retain it alongside any Profile Analyzer .pdata export - the .pdata file does not embed the original profile frames. Module-by-module capture detail, GPU-module platform constraints, and Profile Analyzer setup are in references/unity-profiler.md.
Step 2: Unity - Analyze with Profile Analyzer
Profile Analyzer compares two captures side by side, which the standard Profiler cannot. Open it via Window > Analysis > Profile Analyzer, then run the regression check:
Step 3: Unity - Automated regression with Performance Testing package
Add "com.unity.test-framework.performance": "3.0.3" to Packages/manifest.json and reference Unity.PerformanceTesting in your assembly definition (docs.unity3d.com/Packages/com.unity.test-framework.performance@3.0/manual/index.html (opens in new window)).
Measure.Method (Edit Mode or Play Mode)
[Test, Performance]
public void PathfindingCost_UnderBudget()
{
Measure.Method(() => pathfinder.FindPath(start, goal))
.WarmupCount(5)
.MeasurementCount(20)
.IterationsPerMeasurement(10)
.Run();
}Measure.Frames (Play Mode)
[UnityTest, Performance]
public IEnumerator CombatScene_FrameTime_UnderBudget()
{
yield return Measure.Frames()
.WarmupCount(5)
.MeasurementCount(60)
.Run();
}Target standard deviation below 5%; avoid measurements under 1 ms due to environmental sensitivity.
Decorate tests [Test, Performance] for Edit Mode or [UnityTest, Performance] for Play Mode coroutines. View results via Window > Analysis > Performance Test Report.
GC-spike detection
Enable the ProfilerMarkers method on Measure.Method to target GC.Alloc markers specifically:
Measure.Method(() => SpawnWave())
.ProfilerMarkers("GC.Alloc")
.MeasurementCount(20)
.Run();A passing frame should produce 0 bytes of GC allocation in hot gameplay paths. Any non-zero sample is a regression candidate.
Disable VSync in Project Settings and remove cameras not needed for the measurement to keep results consistent between runs.
Step 4: Unreal - Stat commands for first-pass triage
Unreal Engine stat commands are entered into the PIE console while the game runs (dev.epicgames.com/documentation/en-us/unreal-engine/stat-commands-in-unreal-engine (opens in new window)):
| Command | Shows |
|---|---|
stat fps | Frames per second counter |
stat unit | Frame, Game thread, Draw (render thread), GPU, RHIT, and DynRes times; recommended starting point |
stat gpu | GPU statistics for the frame |
stat scenerendering | General rendering statistics; entry point for rendering bottleneck triage |
stat game | How long the various gameplay ticks are taking |
stat memory | Memory usage by subsystem |
stat unit is the first command to run on any new build: it identifies whether the bottleneck is game-thread, render-thread, or GPU, and measures how long the video card takes to render the scene. Run in a non-debug build for accurate results.
Step 5: Unreal - Deep analysis with Unreal Insights
When stat triage is not enough, capture a full trace with Unreal Insights. Launch it from the Editor's Trace/Insights Status Bar Widget or the prebuilt Engine\Binaries\[Platform]\UnrealInsights.exe binary, then work the CPU/GPU/Memory/Networking trace channels in the Timing Insights and Memory Insights views. The trace channels, the live Session Browser, and the two primary views are detailed in references/unreal-insights.md.
Step 6: GPU draw-call and overdraw budgets
Unity
The GPU Usage module's Hierarchy view shows DrawCalls count and GPU ms per rendering pass (see references/unity-profiler.md). Typical mobile budget: under 100 draw calls per frame; PC/console budget is title-specific but PostProcess and Transparent passes are common over-budget culprits.
Overdraw (multiple pixels written per screen pixel per frame) is visible when Transparent pass GPU ms is disproportionate to scene complexity. Reduce by: lowering particle counts, using depth pre-pass, culling off-screen transparency.
Unreal
Run stat scenerendering to surface general rendering statistics as the entry point for rendering bottleneck identification. Follow with stat gpu to get per-pass GPU time, then use the GPU Visualizer (ProfileGPU console command) for a hierarchical breakdown of GPU passes to isolate overdraw-heavy translucent passes (dev.epicgames.com/documentation/en-us/unreal-engine/gpu-profiling-in-unreal-engine (opens in new window)).
Step 7: CI regression gate
Unity
Run Performance Testing package tests in a headless Unity batch session:
unity -batchmode -runTests -testPlatform StandaloneWindows64 \
-testResults results.xml -projectPath .Parse results.xml; fail the build if any PerformanceMeasurement sample set has a median or p99 exceeding the declared threshold. A zero-tolerance GC.Alloc assertion on hot paths is a recommended gate: one stray allocation per frame compounds to hundreds of KB/s under sustained play.
For stable CI numbers: disable VSync, remove unused cameras, set a fixed Quality level, and disable hardware reporting in Player Settings.
Unreal
Unreal Automation System (see unreal-automation-system) exposes a PerformanceCapture test type. Combine with a CI step that launches Insights in server mode, runs the target map for N frames, exports the trace, and compares the exported GPU/CPU frame time histogram against stored baselines.
Budget report template
Emit one row per profiled scenario per SKU:
| Scenario | SKU | Metric | Budget | Measured (p50) | Measured (p99) | Status |
|---|---|---|---|---|---|---|
| Combat encounter | PC High | Frame time | 16.67 ms | 11.2 ms | 18.4 ms | FAIL p99 |
| Combat encounter | PC High | GC alloc/frame | 0 B | 0 B | 128 B | FAIL p99 |
| Open-world traversal | PC High | Frame time | 16.67 ms | 13.1 ms | 15.9 ms | PASS |
A FAIL on p99 triggers a regression investigation before milestone sign-off.
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Averaging frame time across a level | Spikes hide in averages and cause cert failures | Use p99 and sustained-window maximums |
| Profiling with Graphics Jobs enabled in Unity | GPU module is disabled; no GPU data collected | Disable Graphics Jobs before capture |
| GC alloc tolerance in hot paths | Compounds to MB/s under sustained play | Assert 0 B per frame in CI on hot paths |
| Running perf tests in debug builds (Unreal) | Inaccurate results; use non-debug builds | Profile in Development or Shipping builds |
| Single-device perf sign-off | Low-end SKU (Series S, Switch handheld) is the binding constraint | Run budget checks on every SKU in the compatibility matrix |
Limitations
Unity Profiler capture - module reference
View source (opens in new window)Unity Profiler capture - module reference
Supporting detail for game-perf-profiling Step 1 (capture) and Step 2 (compare). Cited once here rather than repeated in the spine.
The Unity Profiler collects CPU, GPU, and memory data in the Editor or from a connected target device (docs.unity3d.com/Manual/Profiler.html (opens in new window)). Open it via Window > Analysis > Profiler (Ctrl+7).
Key modules to enable for a frame-time pass:
For standalone builds, use Deep Profiling or custom ProfilerMarker instrumentation to capture application-specific events without the full overhead of deep profiling.
Save the capture as a .data file (Profiler toolbar > Save). Retain it alongside any Profile Analyzer .pdata export: the .pdata file does not embed the original profile frames (docs.unity3d.com/Packages/com.unity.performance.profile-analyzer@1.2/manual/index.html (opens in new window)).
Profile Analyzer (package com.unity.performance.profile-analyzer, Unity 2020.3+, install via Package Manager) aggregates and visualizes frame and marker data from a set of Profiler frames, enabling side-by-side comparison of two captures that the standard Profiler does not support. Open it via Window > Analysis > Profile Analyzer. The Analyzer navigates to matching markers in the Profiler when you click a marker entry; make a selection in the Profiler beforehand for navigation to work.
Unreal Insights - deep analysis reference
View source (opens in new window)Unreal Insights - deep analysis reference
Supporting detail for game-perf-profiling Step 5. Cited once here rather than repeated in the spine.
Unreal Insights is a telemetry capture and analysis suite that captures events from a project at high data rates (dev.epicgames.com/documentation/en-us/unreal-engine/unreal-insights-in-unreal-engine (opens in new window)).
Launch from the Editor via the Trace/Insights Status Bar Widget in the bottom toolbar, or from the prebuilt binary at Engine\Binaries\[Platform]\UnrealInsights.exe.
Key trace channels:
| Channel | Captures |
|---|---|
| CPU | Thread-level timing per task and function |
| GPU | Per-frame GPU timing |
| Memory | Allocation, reallocation, and deallocation events |
| Networking | Network traffic for multiplayer titles |
| Slate | UMG/Slate widget update costs |
| Asset loading | Asset load time per type |
Live sessions appear in the Session Browser with a "LIVE" status indicator; Insights supports simultaneous connection to multiple sessions and records streams automatically for later replay.
Primary views:
Related skills
gameplay-recording-replay
Build a deterministic gameplay record/replay test artefact for Unity, Unreal, or Godot - record a player session, save it to disk, replay it bit-for-bit, and assert that the resulting game state matches the original. Covers Unity Input System's InputEventTrace API (Enable / Disable / WriteTo / ReadFrom / Replay) for input-level capture, Unreal's Replay System (DemoRec / DemoPlay / DemoStop console commands plus DemoNetDriver + NetworkReplayStreamer, default storage at %LOCALAPPDATA%/{Project}/Saved/Demos) for replication-stream capture, and Godot's community-pattern deterministic-RNG + input-script replay since Godot ships no first-party replay system. Use when authoring a regression-test artefact for player-recorded sessions, building a netcode replay for spectator / esports, or producing reproducible bug repros for cert teams.
godot-gut-tests
Author and run GUT (Godot Unit Test) - the community-canonical GDScript test framework at github.com/bitwes/Gut and gut.readthedocs.io. Covers install (Godot Asset Library or manual `addons/gut/` copy + plugin enable), GUT panel inside the editor, writing tests that extend GutTest with `test_` prefix methods, the assertion family (assert_eq / assert_almost_eq / assert_true / assert_signal_emitted), lifecycle hooks (before_each / after_each / before_all / after_all), inner classes for grouping, parameterized tests via `params=[...]`, doubles / stubs / spies, async / coroutine tests, the command-line runner (`-d -s addons/gut/gut_cmdln.gd -gdir=res://test -gjunit_xml_file=... -gexit`), JUnit XML export, and CI integration. Godot 4.x uses GUT 9.x (current main branch supports 4.6.x; godot_4_7 branch for 4.7.x); Godot 3.x uses GUT 7.x. Use when the unit under test is GDScript code in a Godot project.
multiplayer-state-machine-coverage
Build a coverage matrix for a networked-game state machine that exercises connect / authority-handoff / disconnect / reconnect / host-migration paths across Unity Netcode for GameObjects, Unreal Engine replication, and Mirror Networking. Workflow: enumerate the engine's connection states + ownership states + replicated-property update rules, cross them against latency / loss / out-of-order packet injection, encode each combination as a test fixture, and emit a go / no-go gate. Use before submitting a multiplayer title to platform cert - Microsoft's cert guide lists 'Multiplayer does not work as expected' as one of the most common Hold reasons, and Xbox XR-067 (MPSD session state) is failed by uncovered state-machine paths.
platform-cert-overview-reference
Reference catalog of game-QA test categories and the four platform-holder certification regimes a multi-platform title submits to before release. Defines the six canonical test categories (functional / compliance / compatibility / performance / localization / accessibility) plus the multiplayer and content-rating cross-axes; documents the submission workflow, severity vocabulary, test-bench configurations, and known SLAs for Microsoft Xbox Requirements (XR), Sony TRC (gated PlayStation DevNet), Nintendo Lotcheck (gated Nintendo Developer Portal), and Steam Direct review; and includes the building-a-cert-checklist workflow that maps a target platform's requirement items to the six categories. Cites public sources inline; cites gated NDA portals by stable ID per PLUGIN_AUTHORING.md Step 4 fallback. Use when planning a game test pass or cert calendar, mapping internal QA findings to the platform's vocabulary, sequencing submissions across platforms, or emitting a pre-submission checklist.
unity-test-framework
Author and run the Unity game-engine Test Framework (`com.unity.test-framework`, currently v1.8). Distinct from the ThrowTheSwitch Unity C testing library at throwtheswitch.org/unity - the two tools share only a name. Covers package install via Package Manager, the EditMode vs PlayMode split, the [Test] / [UnityTest] / [SetUp] / [TearDown] / [UnityPlatform] attributes, assembly-definition setup (Editor folder vs asmdef with `includePlatforms` / `optionalUnityReferences: [TestAssemblies]`), Test Runner window, command-line batch invocation with `-runTests` / `-testPlatform` / `-testResults` / `-testFilter` / `-testCategory`, NUnit 3.5 assertion API, and CI integration. Use when the unit under test is C# Unity code that needs to exercise the Unity runtime or editor.
unreal-automation-system
Author and run Unreal Engine's Automation Test Framework - Epic's C++ test framework for UE 4.x / 5.x, documented at dev.epicgames.com/documentation/en-us/unreal-engine. Covers the five test categories Epic defines (Unit / Feature / Smoke / Content Stress / Screenshot Comparison), the IMPLEMENT_SIMPLE_AUTOMATION_TEST and IMPLEMENT_COMPLEX_AUTOMATION_TEST macros, the BDD-style Automation Spec API (DEFINE_SPEC / BEGIN_DEFINE_SPEC / Describe / It / BeforeEach / LatentIt / xIt), latent commands (ADD_LATENT_AUTOMATION_COMMAND), the Automation Driver for UI input simulation (IAutomationDriverModule::Get().CreateDriver(), By::Id / By::Path locators), running via Session Frontend (Window > Test Automation) and command line (-ExecCmds="Automation RunTests …"), and CI integration. Use when the unit under test is C++ Unreal code that needs the UE runtime, editor, or UMG UI surface.