|
| 1 | +.. _doc_optimization: |
| 2 | + |
| 3 | +Optimization guidelines |
| 4 | +======================= |
| 5 | + |
| 6 | +Introduction |
| 7 | +------------ |
| 8 | + |
| 9 | +In general, the project prefers clear, simple code over highly optimized code, |
| 10 | +except in bottlenecks. |
| 11 | + |
| 12 | +However, optimization PRs are welcome provided they follow the guidelines below. |
| 13 | + |
| 14 | +.. note:: |
| 15 | + |
| 16 | + The project doesn't automatically accept all optimization PRs, even if they |
| 17 | + improve performance. |
| 18 | + |
| 19 | +Choosing what to optimize |
| 20 | +------------------------- |
| 21 | + |
| 22 | +Predicting which code would benefit from optimization can be difficult without |
| 23 | +using performance analysis tools. |
| 24 | + |
| 25 | +Oftentimes code that looks slow has no impact on overall performance, and code |
| 26 | +that looks like it should be fast has a huge impact on performance. Further, |
| 27 | +reasoning about why a certain chunk of code is slow is often impossible to do |
| 28 | +without detailed metrics (e.g. from a profiler). |
| 29 | + |
| 30 | +Instructions on using some common profilers with Godot can be found `here |
| 31 | +<https://docs.godotengine.org/en/stable/engine_details/development/debugging/using_cpp_profilers.html>`_. |
| 32 | + |
| 33 | +As an example, you may optimize a chunk of code by caching intermediate values. |
| 34 | +However, if that code was slow due to memory constraints, caching the values and |
| 35 | +reading them later may be even slower than calculating them from scratch! |
| 36 | + |
| 37 | +Similarly, if the code is relatively slow but is only called rarely (for |
| 38 | +instance once on level load), then there is less potential benefit to speeding |
| 39 | +it up (unless you are specifically optimizing load times). |
| 40 | + |
| 41 | +Most optimizations involve making a tradeoff, so instead of randomly picking a |
| 42 | +part of the engine to optimize, we recommend that you use a profiler to identify |
| 43 | +bottlenecks **before** making any changes to ensure that your optimization will |
| 44 | +make a difference. |
| 45 | + |
| 46 | +If an area of the engine is not appearing in a profile, no matter how |
| 47 | +inefficient the code, then a PR is unlikely to be approved and merged. |
| 48 | + |
| 49 | +*(There are some exceptions, but this is generally the pattern.)* |
| 50 | + |
| 51 | +When in doubt, look for Github issues tagged with the `performance |
| 52 | +<https://github.com/godotengine/godot/issues?q=is%3Aissue%20state%3Aopen%20label%3Aperformance>`_ |
| 53 | +label to guide your optimization efforts. |
| 54 | + |
| 55 | +When assessing optimization opportunities, we need to take into account: |
| 56 | + |
| 57 | +Benefits |
| 58 | +~~~~~~~~ |
| 59 | + |
| 60 | +Is the optimization worth doing in this case? |
| 61 | + |
| 62 | +- How often is this code called? |
| 63 | +- How much of a bottleneck is it to overall performance? |
| 64 | +- Does profiling show it to be a bottleneck? |
| 65 | + |
| 66 | +Costs |
| 67 | +~~~~~ |
| 68 | + |
| 69 | +What are the downsides? |
| 70 | + |
| 71 | +- Code complexity |
| 72 | +- Code readability |
| 73 | +- Maintenance burden |
| 74 | +- Constraining future changes |
| 75 | +- Risk of regressions |
| 76 | + |
| 77 | +Optimization process |
| 78 | +-------------------- |
| 79 | + |
| 80 | +Once you have decided what you should optimize, you should start by capturing a |
| 81 | +baseline profile in your profiler of choice. Ensure you are running Godot's |
| 82 | +latest ``master`` branch and that you use an optimized build of Godot, since many |
| 83 | +things that run slowly in debug end up disappearing with optimizations enabled. |
| 84 | + |
| 85 | +By default, Godot builds with optimizations enabled. See `the Godot build docs |
| 86 | +<https://docs.godotengine.org/en/stable/engine_details/development/compiling/introduction_to_the_buildsystem.html#optimization-level>`_ |
| 87 | +for more information about build optimization settings. |
| 88 | + |
| 89 | +In some cases using a synthetic benchmark is also acceptable, but remember that |
| 90 | +Godot is a game engine. The golden standard is to test the performance of real |
| 91 | +games. Benchmarks can be helpful, but they can also be misleading because it is |
| 92 | +very difficult to create benchmarks that reflect how performant the code will be |
| 93 | +in an actual game. |
| 94 | + |
| 95 | +Once you have your baseline profile/benchmark, make your changes and rebuild the |
| 96 | +engine with the exact same build settings you used before. Then profile again |
| 97 | +and compare the results. |
| 98 | + |
| 99 | +.. note:: |
| 100 | + |
| 101 | + Results will fluctuate, so you'll need to make your test project or |
| 102 | + benchmark intensive enough to isolate the code you're trying to optimize (ideally, |
| 103 | + go for at least 2 seconds of real-life runtime). Additionally, you should run the |
| 104 | + test multiple times, and observe how much the results fluctuate. Fluctuations of up |
| 105 | + to 10% are common and expected. The fastest run is usually the most accurate number. |
| 106 | + |
| 107 | +Pull request requirements |
| 108 | +------------------------- |
| 109 | + |
| 110 | +When making an optimization PR you should: |
| 111 | + |
| 112 | +- Explain why you chose to optimize this code (e.g. include the profiling result, link the issue report, etc.). |
| 113 | +- Show that you improved the code either by profiling again, or running systematic benchmarks. |
| 114 | +- Test on multiple platforms where appropriate, especially mobile. |
| 115 | +- When micro-optimizing, show assembly before / after where appropriate. |
| 116 | + |
| 117 | +In particular, you should be aware that for micro-optimizations, C++ compilers will often |
| 118 | +be aware of basic tricks and will already perform them in optimized builds. This is why |
| 119 | +showing before / after assembly can be important in these cases. |
| 120 | +(`godbolt <https://godbolt.org/>`_ can be particularly useful for this purpose.) |
| 121 | + |
| 122 | +The most important point to get across in your PR is to highlight the source of |
| 123 | +the performance issues, and have a clear explanation for how your PR fixes that |
| 124 | +performance issue. Your profiling/benchmarking results are proof that your |
| 125 | +optimization was successful. |
| 126 | + |
| 127 | +Optimizing for best / worst cases |
| 128 | +--------------------------------- |
| 129 | + |
| 130 | +Often in optimization there can be situations where optimizing for a rare case slows a |
| 131 | +common case, or vice versa. Be aware that surprisingly often in games, optimizing for |
| 132 | +the worst case can be more important than optimizing for the best case, as worst cases |
| 133 | +can cause dropped frames. |
| 134 | + |
| 135 | +In situations where a PR is trading off speed in different paths, reviewers may have to |
| 136 | +decide whether a change is worth making. |
| 137 | + |
| 138 | +GPU optimization |
| 139 | +---------------- |
| 140 | + |
| 141 | +GPU optimization can be even more fraught with difficulty than CPU optimization, |
| 142 | +primarily because of the vast range of hardware the engine must run on, differences in |
| 143 | +drivers and behavior, and aggressive power saving modes that downclock the GPU when |
| 144 | +not under stress. |
| 145 | + |
| 146 | +Even more so than for CPU work, it is essential to test GPU changes on mobile as well as |
| 147 | +desktop, and the more platforms, the better. |
| 148 | + |
| 149 | +In particular, you should be aware that changes which increase performance on one platform |
| 150 | +can often reduce performance on another. |
| 151 | + |
0 commit comments