Skip to content

Commit a3e853e

Browse files
committed
Add a subsection for microbenchmarks to the profiling page.
1 parent 98cd4a4 commit a3e853e

1 file changed

Lines changed: 95 additions & 0 deletions

File tree

  • engine_details/development/profiling

engine_details/development/profiling/index.rst

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,98 @@ All recommended profilers
113113
perfetto
114114
tracy
115115
very_sleepy
116+
117+
Microbenchmarks
118+
---------------
119+
120+
While not technically profiling, microbenchmarks are a related concept: after you've identified
121+
your hotspot, you'll want a simple and isolatable way to test whether what you're doing has an impact.
122+
While re-profiling can be an option, sometimes a microbenchmark can be simpler.
123+
124+
You can see example benchmark setups in the subsections below. Between C++ and GDScript, GDScript
125+
benchmarks are usually the more appropriate choice. Because they involve the GDScript language and
126+
its overhead, GDScript benchmarks are truthful to how most people will experience your changes.
127+
C++ benchmarks are more versatile and can measure smaller performance differences. However, they
128+
are also more difficult to get right.
129+
In practice, it can often be good to benchmark both.
130+
131+
.. note::
132+
133+
To benchmark effectively can be difficult. Benchmarks can easily lead you astray, for example
134+
by not representing the situation faithfully, by failing to account for compiler optimizations
135+
and other nuances, or by measuring in an unreliable way such that you record noise instead of
136+
an actual performance change. Before you start benchmarking, please read up on benchmarking
137+
guides and best practices. A good place to start is Gregg's `"Active Benchmarking" <https://www.brendangregg.com/activebenchmarking.html>`__, which provides a high level overview and quick checklist for
138+
benchmarking.
139+
140+
GDScript Benchmarks
141+
~~~~~~~~~~~~~~~~~~~
142+
143+
To run a GDScript benchmark, start by creating a ``benchmark.gd`` file with the following
144+
contents:
145+
146+
.. code-block:: gdscript
147+
148+
extends SceneTree
149+
150+
func _init():
151+
const N = 1_000_000
152+
153+
var t0 := Time.get_ticks_usec()
154+
for i in N:
155+
pass # Do the thing you want to benchmark here.
156+
var t1 := Time.get_ticks_usec()
157+
158+
var ns_per_op := (t1 - t0) * 1000.0 / N
159+
print("Benchmark result: %.1f ns/op" % ns_per_op)
160+
quit()
161+
162+
Edit the file to add your benchmark.
163+
You can run the benchmark using ``godot --headless -s benchmark.gd``.
164+
165+
.. note::
166+
167+
At the time of writing, GDScript performs few code optimization. Dead code elimination,
168+
for example, is generally not performed. Therefore, it is easier to write a decently
169+
representative benchmark in GDScript than in C++. This might change in the future. You
170+
can find free in-depth guides in Bakhvalov's `"Performance Analysis and Tuning on Modern CPUs" <https://github.com/dendibakh/perf-book>`__, and Agner Fog's `"Software Optimization Resources" <https://www.agner.org/optimize/>`__.
171+
172+
C++ Benchmarks
173+
~~~~~~~~~~~~~~
174+
175+
To run a C++ benchmark, create the file ``tests/core/test_user_bench.cpp`` with the following contents:
176+
177+
.. code-block:: cpp
178+
179+
#include "tests/test_macros.h"
180+
181+
TEST_FORCE_LINK(test_user_bench)
182+
183+
#include <chrono>
184+
#include <cstdio>
185+
186+
static void user_bench() {
187+
const int N = 1'000'000;
188+
static uintptr_t sink = 0; // Defeats dead-code elimination.
189+
190+
auto t0 = std::chrono::steady_clock::now();
191+
for (int i = 0; i < N; i++) {
192+
// Do the thing you want to benchmark here.
193+
// sink += (uintptr_t)something; // Update the sink from the result somehow.
194+
}
195+
auto t1 = std::chrono::steady_clock::now();
196+
197+
double ns_per_op = std::chrono::duration<double, std::nano>(t1 - t0).count() / N;
198+
printf("Benchmark result: %.1f ns/op (sink %zu)\n", ns_per_op, (size_t)sink);
199+
}
200+
201+
REGISTER_TEST_COMMAND("user-bench", &user_bench)
202+
203+
Edit the file to add your benchmark.
204+
Compile Godot with ``tests=yes``, and run the benchmark using ``godot --test user-bench``.
205+
206+
.. note::
207+
208+
C++ benchmarks can be fickle and can easily lead you astray unless you have a strong
209+
foundation of knowledge about C++ and compilers. Before you start benchmarking, read
210+
up on guides and best practices about how to benchmark C++.

0 commit comments

Comments
 (0)