- 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}` is the nearest folder containing `_bmad/`, starting at the project working directory and moving up through its parents.
- `{skill-name}` resolves to the skill directory's basename.
## On Activation
### Step 1: Resolve the Workflow Block
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-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
<workflow>
<step n="1" goal="Define Performance Targets">
<action>Detect game engine and target platforms from project files. If ambiguous, ask the user.</action>
<action>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.
</action>
<action>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 |
</action>
<action>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).
</action>
</step>
<step n="2" goal="Identify Test Scenarios">
<action>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
```
</action>
<action>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
```
</action>
<action>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
```
</action>
<action>Adapt scenario details to match the specific game type and identified systems</action>
</step>
<step n="3" goal="Define Test Methodology">
<action>Generate automated performance test code for the detected engine</action>
<check if="engine == 'unity'">
<action>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");
}
```
</action>
</check>
<check if="engine == 'unreal'">
<action>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<AStressTestActor>();
float FrameTime = FApp::GetDeltaTime();
TestTrue("Frame time under budget", FrameTime < 0.033f);
return true;
}
```
</action>
</check>
<check if="engine == 'godot'">
<action>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)")
```
</action>
</check>
<action>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
</action>
</step>
<step n="4" goal="Create Benchmark Suite">
<action>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.
</action>
<action>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
</action>
</step>
<step n="5" goal="Platform-Specific Testing">
<action>Define platform-specific testing requirements for each target platform</action>
<check if="platform includes 'pc'">
<action>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)
</action>
</check>
<check if="platform includes 'console'">
<action>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)
</action>
</check>
<check if="platform includes 'mobile'">
<action>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
</action>
</check>
</step>
<step n="6" goal="Generate Performance Test Plan">
<action>Load `{template}` and use it as the structural foundation for the output document</action>
<action>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]
```
</action>
<action>Load and apply `{validation}` checklist to verify all deliverables are complete</action>
<action>Present a summary of what was produced and the recommended next steps to the user</action>
<action>Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
</step>
</workflow>
Ver en GitHub