Profiling & Shipping
Finding where the frame time actually goes, keeping the asset pipeline honest, and everything between a working build and a released game.
The Last Twenty Percent
Performance here is a budget, not a score. At 60 fps a frame is 16.6 ms, and every system spends part of it. Once the budget is written down, optimisation becomes a matter of finding who overspent instead of a general anxiety about speed.
Profiling
Measure before changing anything. Intuition about where time goes is wrong often enough that acting on it wastes days and sometimes makes the frame slower.
The first question is always CPU-bound or GPU-bound, because the answers have nothing in common. Drop the resolution: if the frame rate improves, you are GPU-bound and the work is in shaders, overdraw and fill rate. If nothing changes, you are CPU-bound and the work is in game logic, physics and draw call submission.
| Symptom | Usual cause |
|---|---|
| Low average frame rate | Too much per-frame work — profile and budget it |
| Periodic hitches | Garbage collection, or loading on the main thread |
| Slow only on one platform | Memory bandwidth or fill rate, not logic |
| Degrades as the level fills | An O(n²) system — usually collision or AI queries |
Allocation is the usual source of hitches in a managed language. Allocating inside the frame loop hands work to the garbage collector, which eventually stops the world at the least convenient moment. Pool objects and reuse buffers instead of allocating per frame.
The Asset Pipeline
Assets outweigh code by orders of magnitude, and the pipeline that turns source art into shipped data decides both load times and download size — the two numbers that most affect whether anyone plays past the first minute.
| Concern | Practice |
|---|---|
| Textures | GPU-compressed formats per platform, with mipmaps |
| Audio | Compressed for music, uncompressed for short frequent effects |
| Meshes | Level-of-detail chains so distant objects cost less |
| Source art | Version-controlled with LFS, never the imported output |
| Loading | Streamed in the background, never on the main thread |
Import settings are where builds quietly go wrong: an uncompressed 4K texture on a background prop, or a fully decompressed music track resident in memory, costs more than any amount of code optimisation will recover. Audit them, and keep the import step automated so nobody has to remember.
Platforms & Release
Every console platform has a certification process: a list of technical requirements covering suspend and resume, controller disconnection, save data corruption, storage-full handling, age ratings and terminology. Failing it means resubmission and weeks of delay, so it is read at the start of a project rather than the end.
| Target | Watch for |
|---|---|
| PC | Unbounded hardware variance, drivers, alt-tab and windowing |
| Console | Certification, fixed memory budgets, mandated behaviours |
| Mobile | Thermal throttling, battery, interruptions, tiny memory |
| Web | Download size, browser APIs, no threads for free |
Mobile deserves special care because sustained performance is not peak performance. A device hits its thermal limit after a few minutes and downclocks — a game that benchmarks at 60 fps can settle at 35 fps once the phone is warm, and that is the number players experience.
Ship with crash reporting and telemetry from day one. Where players quit, which levels take four attempts, which GPU crashes — none of it can be recovered after release if it was not being recorded. And build the release candidate on CI, not on a developer's machine: a build nobody can reproduce is a build nobody can fix.
Interview Questions
How do you tell CPU-bound from GPU-bound?
Lower the resolution. If the frame rate improves the GPU was the limit; if it does not move, the CPU is, and the work is in logic, physics or draw call submission.
Why track the 99th percentile rather than the average?
Players feel the worst frames. A steady 45 fps is more comfortable than 60 fps with periodic 200 ms stalls, and an average hides exactly that.
What causes periodic hitches in a managed language?
Allocation inside the frame loop. The garbage collector eventually runs and pauses the game — pooling objects and reusing buffers removes the cause rather than the symptom.
Why do import settings matter so much?
They decide runtime memory and load times. An uncompressed 4K texture on a background prop costs more than most code optimisations will ever recover.
What does console certification cover?
Technical requirements — suspend and resume, controller disconnection, save data handling, storage-full cases, ratings and terminology. Failing means resubmission and weeks of delay.
Why is mobile performance different?
Thermal throttling. A device downclocks after a few minutes of load, so sustained frame rate is well below the benchmarked peak, and that is what players actually get.