Wikipedia defines “optimization” as the process of modifying a system to make some aspect of it work more efficiently or use fewer resources. Each game has a certain fixed amount of computing resources available to it. Within that world of possibility, the developer must create a compelling experience. Market force dictate that it must be as good an experience as possible.
Why optimize your code ? When you optimize your code, you’re increasing the amount of work you are able to do per unit of computational power and maximizing your efficiency. By optimizing your CPU and GPU usage, you can add more polygons, more pixels, more physics, more AI , more responsiveness, more immersion-leading to more fun and better visuals, the elements that help make and sell revolutionary video games.
The optimization process is simple. Start by looking at the whole system. Find a situation that consistently exhibits bad performance. That done, measure where resource are being used. Take steps to reduce them. Finally, measure again to see if you have improved the situation sufficiently. If it’s good enough, you’re done. Otherwise, find the next performance problem and start all over again.
The optimizer’s mantra :
[fruitful_tabs type=”default” width=”100%” fit=”false”]
[fruitful_tab title=”Benchmark”] Create a repeatable example of a problem situation. [/fruitful_tab]
[fruitful_tab title=”Measure”] Establish a baseline of memory and compute resource usage. [/fruitful_tab]
[fruitful_tab title=”Detect”] Find the part of the program that is mis-using the resources.[/fruitful_tab]
[fruitful_tab title=”Solve”] Change how the program works to improve resource usage.[/fruitful_tab]
[fruitful_tab title=”Check “] Determine if there was an improvement through measurement.[/fruitful_tab]
[fruitful_tab title=”Repeat “] Do the process over and over again until you hit your performance goals.[/fruitful_tab]
Getting to Better Optimization
Anyone can follow the basic optimization process and eventually get a game to run faster. You will find that experience, skill, and knowledge are necessities. Your will also need to use your intuition and your patience. Optimization is a crucial step to building compelling games.
Using your intuition involves assumptions. The downfall of novice optimizers is that they don’t know the assumptions under which they are operating. Their intuition misleads them. They may assume, for example , that inline code always makes it run faster, or that garbage collection is always slower than manual memory allocation. The expert optimizer understand his assumptions, and they knows when to question them-and better still, realizes that they are fallible and must build assumptions based on measurements and analysis.
The difference between a novice and master chess player isn’t how quickly they move their pieces. The difference is that the master chess player immediately identifies the key details of the situation. Both players try to look several moves ahead, but the master only thinks about the moves that will likely lead to victory.
In optimization, there are a million different things you can do to speed up your code. A beginner will struggle because he has to try a lot of approaches , and may not hit on the things most likely to give big performance wins.
On the other hand, good optimizers are able to quickly identify the three or four things that will make the biggest difference, measure their effects, and choose the best from among them.
Optimization is a cycle that you repeat until your game is fast enough.
All optimization starts with a benchmark. Once a benchmark is found, it’s possible to profile, identify the performance problem, and solve it. Finally, we return to our benchmark to see if we have improved performance.
When you’re optimizing, it’s essential that you be able to measure your gains. For a game, a benchmark is a point of reference in your game that serves as a standard for comparison against future implementations. A good benchmark will have a few important qualities.
First, it will be consistent across runs. Running the benchmark twice without changing your code should give your the same results.
Second, it will be quick. It shouldn’t take more than a minute or so to run the benchmark; otherwise, you’ll spend more time waiting on the test than working on the fix.
Third, it should be representative of an actual game situation, so you don’t waste time optimizing for scenarios that will never arise.
Finally, it will be responsive to changes. It should be obvious when you’ve fixed the performance problem.
Anytime, you start to optimize something, make sure that you can measure your success.
This step is to gather and analyze data to help identify where you need to optimize. Performance increase with the least amount of effort. In other words, you are looking for the biggest return on your time investments.
In optimization, you always start at the big picture and work your way down to the fine grain problem. The first big division is typically finding out whether the CPU or the GPU is slowing you down more; sometimes the CPU and GPU are equally balanced.
After you’ve gathered enough information to identify the factor limiting your performance, then you can change something to try to improve the performance. You might toggle a flag, rewrite an algorithm, or change the data you are loading. Example, we notice that there’s a loop that’s not updating correctly, and as a result, it’s running far too often. We expect that fixing it will win us back a lot of waster CPU cycles, so we go ahead and make the change.
Even the most experienced optimizer will often have to guess at the best solution. The best practice is always to try several options before settling on a solution.
Run your benchmark again and observe the change, see if it really did give a performance win. A common trap for novice optimizer is changing code blindly based on an assumption ( for instance, “inline functions are faster”) without evaluating the effectiveness of the tactic.
Measuring has another benefit too. It develops your intuition, giving you data that will help you optimize more effectively next time you encounter a problem. This corrective action will help you optimize even in the strangest situations on weird hardware, sharing time with odd processes, or even on future architectures.
In a river, when you remove a rock, the water flows in a new way, down to the new path of least resistance. Computer programs are the same.
Removing a bottleneck or a hotspot causes cascades and ripples across the entire performance picture. In other words, every change affects the flow of the program. Your old measurements, and therefore your analysis, may no longer be valid.
After a successful frame rate increase, it’s time to begin the process again. You may need to create a new benchmark, but you can always repeat the detection process and begin your search for the new, slowest part of your game.