--- name: gds-performance-test description: 'Design game performance testing strategy. Use when the user says "performance test" or "benchmark"' --- # Performance Testing Strategy Workflow **Goal:** Design a comprehensive performance testing strategy covering frame rate, memory usage, loading times, and platform-specific requirements. Performance directly impacts player experience — this workflow produces a concrete plan with automated tests, benchmark scenarios, and platform matrices. **Your Role:** You are a senior game performance engineer and QA strategist. Work with the user to identify their platforms, performance requirements, and representative content, then produce a strategy that combines automated profiling, manual testing checklists, and CI-integrated benchmarks. --- ## Conventions - Bare paths (e.g. `template.md`) resolve from the skill root. - `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives). - `{project-root}`-prefixed paths resolve from the project working directory. - `{skill-name}` resolves to the skill directory's basename. ## On Activation ### Step 1: Resolve the Workflow Block Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow` **If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver: 1. `{skill-root}/customize.toml` — defaults 2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides 3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append. ### Step 2: Execute Prepend Steps Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding. ### Step 3: Load Persistent Facts Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim. ### Step 4: Load Config Load config from `{project-root}/_bmad/gds/config.yaml` and resolve: - `project_name` - `user_name` - `communication_language` - `output_folder` ### Step 5: Greet the User Greet `{user_name}`, speaking in `{communication_language}`. ### Step 6: Execute Append Steps Execute each entry in `{workflow.activation_steps_append}` in order. Activation is complete. If `activation_steps_prepend` or `activation_steps_append` were non-empty, confirm every entry was executed in order before proceeding. Do not begin the main workflow until all activation steps have been completed. ## WORKFLOW ARCHITECTURE This uses an **inline workflow pattern** for autonomous execution: - Steps execute sequentially, building toward a complete performance test plan document - Platform detection and target configuration drive all subsequent decisions - The final deliverable is a comprehensive Performance Test Plan document - Knowledge base reference: `knowledge/performance-testing.md` ### Preflight Requirements Before proceeding, verify: - Target platforms identified (or discoverable from project files) - Performance requirements known (target FPS, memory limits), or to be defined in Step 1 - Representative content available for testing - Profiling tools accessible ### Paths - `installed_path` = `{skill_root}` - `validation` = `{installed_path}/checklist.md` - `template` = `{installed_path}/performance-template.md` - `default_output_file` = `{output_folder}/performance-test-plan.md` ### Variables - `target_fps` = `60` (configurable per platform in Step 1) - `target_platform` = `auto` (options: `auto`, `pc`, `console`, `mobile`) - `game_engine` = `auto` (options: `auto`, `unity`, `unreal`, `godot`) --- ## EXECUTION Detect game engine and target platforms from project files. If ambiguous, ask the user. Establish frame rate targets per platform: | Platform | Target FPS | Minimum FPS | Notes | | ----------------- | ---------- | ----------- | ------------------ | | PC (High) | 60+ | 30 | Uncapped option | | PC (Low) | 30 | 30 | Scalable settings | | PS5/Xbox X | 60 | 60 | Performance mode | | PS4/Xbox One | 30 | 30 | Locked | | Switch Docked | 30 | 30 | Stable | | Switch Handheld | 30 | 25 | Power saving | | Mobile (High) | 60 | 30 | Device dependent | | Mobile (Standard) | 30 | 30 | Thermal throttling | Filter this table to the user's actual target platforms. Adjust targets based on game genre and user input. Establish memory budgets per target platform: | Platform | Total RAM | Game Budget | Notes | | ------------- | --------- | ----------- | ------------------- | | PC (Min spec) | 8 GB | 4 GB | Leave room for OS | | PS5 | 16 GB | 12 GB | Unified memory | | Xbox Series X | 16 GB | 13 GB | With Smart Delivery | | Switch | 4 GB | 2.5 GB | Tight constraints | | Mobile | 4-6 GB | 1.5-2 GB | Background apps | Establish loading time targets: | Scenario | Target | Maximum | | ------------ | ------ | ------- | | Initial boot | < 10s | 30s | | Level load | < 15s | 30s | | Fast travel | < 5s | 10s | | Respawn | < 3s | 5s | Adjust based on genre (e.g., fast travel may not apply to linear games). Define stress test scenarios for frame rate validation: ``` SCENARIO: Maximum Entity Count GIVEN game level with normal enemy spawn WHEN enemy count reaches 50+ THEN frame rate stays above minimum AND no visual artifacts AND audio doesn't stutter SCENARIO: Particle System Stress GIVEN combat with multiple effects WHEN 20+ particle systems active THEN frame rate degradation < 20% AND memory allocation stable SCENARIO: Draw Call Stress GIVEN level with maximum visible geometry WHEN camera shows worst-case view THEN frame rate stays above minimum AND no hitching or stuttering ``` Define memory test scenarios: ``` SCENARIO: Extended Play Session GIVEN game running for 4+ hours WHEN normal gameplay occurs THEN memory usage remains stable AND no memory leaks detected AND no crash from fragmentation SCENARIO: Level Transition GIVEN player completes level WHEN transitioning to new level THEN previous level fully unloaded AND memory baseline returns AND no cumulative growth ``` Define loading test scenarios: ``` SCENARIO: Cold Boot GIVEN game not in memory WHEN launching game THEN reaches interactive state in < target AND loading feedback shown AND no apparent hang SCENARIO: Save/Load Performance GIVEN large save file (max progress) WHEN loading save THEN completes in < target AND no corruption AND gameplay resumes smoothly ``` Adapt scenario details to match the specific game type and identified systems Generate automated performance test code for the detected engine Generate Unity Performance Test Runner examples: ```csharp [UnityTest] public IEnumerator Performance_CombatScene_MaintainsFPS() { using (Measure.ProfilerMarkers(new[] { "Main Thread" })) { SceneManager.LoadScene("CombatStressTest"); yield return new WaitForSeconds(30f); } var metrics = Measure.Custom(new SampleGroupDefinition("FPS")); Assert.Greater(metrics.Median, 30, "FPS should stay above 30"); } ``` Generate Unreal Automation test examples: ```cpp bool FPerformanceTest::RunTest(const FString& Parameters) { float StartTime = FPlatformTime::Seconds(); for (int i = 0; i < 100; i++) GetWorld()->SpawnActor(); float FrameTime = FApp::GetDeltaTime(); TestTrue("Frame time under budget", FrameTime < 0.033f); return true; } ``` Generate Godot benchmark test examples: ```gdscript func test_performance_entity_stress(): var frame_times = [] for i in range(100): var entity = stress_entity.instantiate() add_child(entity) for i in range(300): await get_tree().process_frame frame_times.append(Performance.get_monitor(Performance.TIME_PROCESS)) var avg_frame_time = frame_times.reduce(func(a, b): return a + b) / frame_times.size() assert_lt(avg_frame_time, 0.033, "Average frame time under 33ms (30 FPS)") ``` Define manual profiling checklists: **CPU Profiling** - [ ] Identify hotspots using engine profiler - [ ] Check GC frequency and allocation pressure - [ ] Verify multithreading usage and thread contention **GPU Profiling** - [ ] Draw call count at target scenes - [ ] Overdraw analysis on complex areas - [ ] Shader complexity assessment **Memory Profiling** - [ ] Heap allocation patterns over a 30-minute session - [ ] Asset memory usage by category - [ ] Leak detection across multiple level loads Define the benchmark levels and their purpose: | Benchmark | Purpose | Duration | | --------------- | ------------------------ | -------- | | Combat Stress | Max entities, effects | 60s | | Open World | Draw distance, streaming | 120s | | Menu Navigation | UI performance | 30s | | Save/Load | Persistence performance | 30s | Adapt benchmark names and durations to match the actual game content. Define baseline capture process: 1. Run benchmarks on reference hardware (document hardware specs) 2. Record baseline metrics (avg FPS, P95 frame time, peak memory) 3. Set regression thresholds (e.g., 10% FPS degradation = fail, 5% memory growth = fail) 4. Integrate benchmarks into CI pipeline as gated checks Define platform-specific testing requirements for each target platform PC testing requirements: - Test across min/recommended hardware specs - Verify quality settings (Low/Medium/High/Ultra) all perform within budget - Check VRAM usage at each quality tier - Test at multiple resolutions (1080p, 1440p, 4K) Console testing requirements: - Test in both Performance and Quality modes if applicable - Verify thermal throttling behavior during extended sessions - Check suspend/resume impact on frame rate and memory - Test with varying storage speeds (internal SSD vs extended storage) Mobile testing requirements: - Test on low/mid/high tier representative devices - Monitor thermal throttling onset time and severity - Measure battery drain per hour of gameplay - Test with background apps consuming memory Load `{template}` and use it as the structural foundation for the output document Compile all information from Steps 1-5 into a comprehensive Performance Test Plan at `{default_output_file}` with this structure: ```markdown # Performance Test Plan: {project_name} ## Performance Targets [FPS tables filtered to target platforms] [Memory budget tables] [Loading time targets] ## Test Scenarios ### Frame Rate Tests [Stress test scenarios from Step 2] ### Memory Tests [Extended play and leak detection scenarios] ### Loading Tests [Boot, level load, save/load scenarios] ## Methodology ### Automated Tests [Engine-specific code examples] [CI integration instructions] ### Manual Profiling [Checklists from Step 3] [Tools to use per engine] ## Benchmark Suite [Benchmark definitions from Step 4] [Baseline capture process] [Regression thresholds] ## Platform Matrix [Platform-specific requirements from Step 5] ## Regression Criteria [Quantified thresholds: FPS drop %, memory growth %, load time delta] [CI gate configuration] ## Schedule [When performance tests run: nightly, per-sprint, pre-release] [Who reviews results and owns regressions] ``` Load and apply `{validation}` checklist to verify all deliverables are complete Present a summary of what was produced and the recommended next steps to the user Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.