Skip to content

Commit faf527e

Browse files
authored
Merge pull request #7 from lawnjelly/optimization_prs
Engine optimization PR guidelines
2 parents 1744405 + 23e7b57 commit faf527e

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed

engine/guidelines/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This section explains guidelines for contributing to the engine.
1010
:name: sec-engine-contribution-guidelines
1111

1212
best_practices
13+
optimization
1314
cpp_usage_guidelines
1415
code_style
1516
editor_style_guide

engine/guidelines/optimization.rst

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
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

Comments
 (0)