Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Использование профилировщиков C++
Чтобы оптимизировать производительность Godot, нужно знать, что именно оптимизировать в первую очередь. Для этого полезны профилировщики.
Примечание
В редакторе есть встроенный профилировщик GDScript, но использование профилировщика C++ может быть полезно в случаях, когда профилировщик GDScript недостаточно точен или в нём отсутствует информация из-за ошибок в профилировщике.
Существует два основных типа профилировщиков: сэмплирующие и трассирующие.
Сэмплирующие профилировщики периодически прерывают выполняемую программу и берут «сэмпл», который записывает, какие функции выполняются. Используя эту информацию, профилировщик оценивает, в каких функциях программа проводила больше всего времени.
Трассирующие профилировщики работают, записывая события, специфичные для приложения (например, начало и конец одного кадра), создавая лог, называемый «трассой». Профилировщик может использовать трассу для построения графика, отображающего точную высокоуровневую временную шкалу происходящего. Однако любой код, который не был явно инструментирован, не появится на временной шкале трассирующего профилировщика!
Godot поддерживает как сэмплирующие, так и трассирующие профилировщики и уже включает код логирования для общих событий Godot для использования с трассирующим профилировщиком!
Разные проблемы может быть проще отлаживать с помощью одного типа профилировщика по сравнению с другим, но трудно предложить набор правил, какой использовать. Попробуйте оба и посмотрите, что вы сможете из них узнать!
Сэмплирующие профилировщики
Мы рекомендуем следующие сэмплирующие профилировщики:
VerySleepy (только Windows)
Hotspot (только Linux)
Instruments (только Apple)
Эти профилировщики, возможно, не самые мощные или гибкие варианты, но их автономная работа и ограниченный набор функций, как правило, делают их более простыми в использовании.
Настройка Godot
Для получения полезной информации о профилировании абсолютно необходимо использовать сборку Godot, включающую отладочные символы. Официальные исполняемые файлы не содержат отладочных символов, поскольку они значительно увеличат размер загружаемого файла.
Чтобы получить данные профилирования, которые наилучшим образом соответствуют производственной среде (но с отладочными символами), следует скомпилировать двоичные файлы с параметрами production=yes debug_symbols=yes SCons.
Можно запустить профилировщик на менее оптимизированных сборках (например, target=template_debug без LTO), но результаты, естественно, будут менее репрезентативны для реальных условий.
Предупреждение
Не удаляйте отладочную символику из двоичных файлов с помощью команды strip после их компиляции. В противном случае вы больше не получите полезной информации о профилировании при запуске профилировщика.
Сравнительный анализ времени запуска/выключения
Если вы хотите оптимизировать производительность запуска и завершения Godot, вы можете указать профилировщику использовать параметр командной строки --quit для исполняемого файла Godot. Это завершит Godot сразу после его запуска. Параметр --quit работает с --editor, --project-manager или --path <путь к каталогу проекта> (который запускает проект напрямую).
См. также
Дополнительные аргументы командной строки, поддерживаемые Godot, см. в Руководство по командной строке.
Трассирующие профилировщики
В настоящее время Godot поддерживает три трассирующих профилировщика:
Instruments (только Apple)
Примечание
Perfetto является системой трассировки по умолчанию для Android, поэтому предварительно собранные шаблоны экспорта со встроенным и включённым Perfetto предоставляются на странице релизов GitHub.
Чтобы использовать любой из них, вам нужно будет собрать движок из исходного кода. Если вы никогда не делали этого раньше, прочитайте эту документацию для платформы, на которой вы хотите проводить профилирование. Вам нужно будет выполнить те же шаги, но с некоторыми дополнительными аргументами для scons.
Все рекомендуемые профилировщики
Microbenchmarks
While not technically profiling, microbenchmarks are a related concept: after you've identified your hotspot, you'll want a simple and isolatable way to test whether what you're doing has an impact. While re-profiling can be an option, sometimes a microbenchmark can be simpler.
You can see example benchmark setups in the subsections below. Between C++ and GDScript, GDScript benchmarks are usually the more appropriate choice. Because they involve the GDScript language and its overhead, GDScript benchmarks are truthful to how most people will experience your changes. C++ benchmarks are more versatile and can measure smaller performance differences. However, they are also more difficult to get right. In practice, it can often be good to benchmark both.
Примечание
To benchmark effectively can be difficult. Benchmarks can easily lead you astray, for example by not representing the situation faithfully, by failing to account for compiler optimizations and other nuances, or by measuring in an unreliable way such that you record noise instead of an actual performance change. Before you start benchmarking, please read up on benchmarking guides and best practices. A good place to start is Gregg's "Active Benchmarking", which provides a high level overview and quick checklist for benchmarking.
GDScript benchmarks
To run a GDScript benchmark, start by creating a benchmark.gd file with the following
contents:
extends SceneTree
func _init():
const N = 1_000_000
var t0 := Time.get_ticks_usec()
for i in N:
pass # Do the thing you want to benchmark here.
var t1 := Time.get_ticks_usec()
var ns_per_op := (t1 - t0) * 1000.0 / N
print("Benchmark result: %.1f ns/op" % ns_per_op)
quit()
Edit the file to add your benchmark.
You can run the benchmark using godot --headless -s benchmark.gd.
Примечание
At the time of writing, GDScript performs few code optimization. Dead code elimination, for example, is generally not performed. Therefore, it is easier to write a decently representative benchmark in GDScript than in C++. This might change in the future.
C++ benchmarks
To run a C++ benchmark, create the file tests/core/test_user_bench.cpp with the following contents:
#include "tests/test_macros.h"
TEST_FORCE_LINK(test_user_bench)
#include <chrono>
#include <cstdio>
static void user_bench() {
const int N = 1'000'000;
static uintptr_t sink = 0; // Defeats dead-code elimination.
auto t0 = std::chrono::steady_clock::now();
for (int i = 0; i < N; i++) {
// Do the thing you want to benchmark here.
// sink += (uintptr_t)something; // Update the sink from the result somehow.
}
auto t1 = std::chrono::steady_clock::now();
double ns_per_op = std::chrono::duration<double, std::nano>(t1 - t0).count() / N;
printf("Benchmark result: %.1f ns/op (sink %zu)\n", ns_per_op, (size_t)sink);
}
REGISTER_TEST_COMMAND("user-bench", &user_bench)
Edit the file to add your benchmark.
Compile Godot with tests=yes, and run the benchmark using godot --test user-bench.
Примечание
C++ benchmarks can be fickle and can easily lead you astray unless you have a strong foundation of knowledge about C++ and compilers. Before you start benchmarking, read up on guides and best practices about how to benchmark C++. You can find free in-depth guides in Bakhvalov's "Performance Analysis and Tuning on Modern CPUs", and Agner Fog's "Software Optimization Resources".