diff --git a/engine/guidelines/optimization.rst b/engine/guidelines/optimization.rst index 2e44fc1..32dd21b 100644 --- a/engine/guidelines/optimization.rst +++ b/engine/guidelines/optimization.rst @@ -20,16 +20,13 @@ Choosing what to optimize ------------------------- Predicting which code would benefit from optimization can be difficult without -using performance analysis tools. +using performance analysis `tools <#tools-for-optimization>`_. Oftentimes code that looks slow has no impact on overall performance, and code that looks like it should be fast has a huge impact on performance. Further, reasoning about why a certain chunk of code is slow is often impossible to do without detailed metrics (e.g. from a profiler). -Instructions on using some common profilers with Godot can be found `here -`_. - As an example, you may optimize a chunk of code by caching intermediate values. However, if that code was slow due to memory constraints, caching the values and reading them later may be even slower than calculating them from scratch! @@ -96,6 +93,50 @@ Once you have your baseline profile/benchmark, make your changes and rebuild the engine with the exact same build settings you used before. Then profile again and compare the results. +Tools for optimization +~~~~~~~~~~~~~~~~~~~~~~ + +Profilers +^^^^^^^^^ + +Profilers are the most important tool for everyone optimizing code. They show you which +parts of the code are responsible for slow execution or heavy CPU load. Profilers are +therefore excellent for identifying what needs to be optimized, and to test whether +performance was improved after making changes. Godot has a built-in profiler, but it +does not provide very detailed information. Instead, use dedicated C++ profilers, which are +`explained in the Godot documentation `__. + +Benchmarks +^^^^^^^^^^ + +Benchmarks can be a good tool to test the impact of your changes of an isolated piece +of code. However, they can be misleading because it's easy to write them in a way that +doesn't reflect real-world performance. When using benchmarks to test the performance +of your code, always be aware of their potential caveats, and familiarize yourself +with good benchmark practices. + +To start writing benchmarks in Godot, you can use the following code templates: + +.. tabs:: + .. code-tab:: gdscript GDScript + + var start = Time.get_ticks_msec() + var s := "Lorem ipsum dolor sit amet"; + for i in range(10000): + s.replace("e", "b") # Benchmarks the 'replace' function. + print(Time.get_ticks_msec() - start, "ms") + + .. code-tab:: cpp + + String s = "Lorem ipsum dolor sit amet"; + + auto t0 = std::chrono::high_resolution_clock::now(); + for (int i = 0; i < 100000; i ++) { + String s1 = s.replace("e", "b"); // Benchmarks the 'replace' function. + } + auto t1 = std::chrono::high_resolution_clock::now(); + std::cout << std::chrono::duration_cast(t1 - t0).count() << "ms\n"; + .. note:: Results will fluctuate, so you'll need to make your test project or @@ -103,6 +144,22 @@ and compare the results. go for at least 2 seconds of real-life runtime). Additionally, you should run the test multiple times, and observe how much the results fluctuate. Fluctuations of up to 10% are common and expected. The fastest run is usually the most accurate number. + When you're not sure you understand the benchmark results, using assembly viewers + can be useful. + +Assembly viewers +^^^^^^^^^^^^^^^^ + +When making low level optimizations, it can be a good idea to investigate the machine code +generated by the compiler. Assembly viewers make this possible, by showing it in a human +readable form called assembly. Viewing assembly allows you to compare the machine code +before and after your changes, to confirm hypotheses used to guide optimization, and to +see what the compiler is doing in general. + +You may find the following resources useful: + +* Agner Fog's `software optimization resources `__, especially his `C++ optimization guide `__. +* `Compiler Explorer `__, a popular multi-architecture assembly viewer. Pull request requirements ------------------------- @@ -111,13 +168,8 @@ When making an optimization PR you should: - Explain why you chose to optimize this code (e.g. include the profiling result, link the issue report, etc.). - Show that you improved the code either by profiling again, or running systematic benchmarks. + See `tools <#tools-for-optimization>`__ for more info. - Test on multiple platforms where appropriate, especially mobile. -- When micro-optimizing, show assembly before / after where appropriate. - -In particular, you should be aware that for micro-optimizations, C++ compilers will often -be aware of basic tricks and will already perform them in optimized builds. This is why -showing before / after assembly can be important in these cases. -(`godbolt `_ can be particularly useful for this purpose.) The most important point to get across in your PR is to highlight the source of the performance issues, and have a clear explanation for how your PR fixes that