diff --git a/engine_details/development/debugging/img/cpp_profiler_hotspot_flame_graph.png b/engine_details/development/debugging/profiling/img/cpp_profiler_hotspot_flame_graph.png similarity index 100% rename from engine_details/development/debugging/img/cpp_profiler_hotspot_flame_graph.png rename to engine_details/development/debugging/profiling/img/cpp_profiler_hotspot_flame_graph.png diff --git a/engine_details/development/debugging/img/cpp_profiler_hotspot_record.png b/engine_details/development/debugging/profiling/img/cpp_profiler_hotspot_record.png similarity index 100% rename from engine_details/development/debugging/img/cpp_profiler_hotspot_record.png rename to engine_details/development/debugging/profiling/img/cpp_profiler_hotspot_record.png diff --git a/engine_details/development/debugging/img/cpp_profiler_hotspot_view_results.png b/engine_details/development/debugging/profiling/img/cpp_profiler_hotspot_view_results.png similarity index 100% rename from engine_details/development/debugging/img/cpp_profiler_hotspot_view_results.png rename to engine_details/development/debugging/profiling/img/cpp_profiler_hotspot_view_results.png diff --git a/engine_details/development/debugging/img/cpp_profiler_hotspot_welcome.png b/engine_details/development/debugging/profiling/img/cpp_profiler_hotspot_welcome.png similarity index 100% rename from engine_details/development/debugging/img/cpp_profiler_hotspot_welcome.png rename to engine_details/development/debugging/profiling/img/cpp_profiler_hotspot_welcome.png diff --git a/engine_details/development/debugging/profiling/img/cpp_profiler_perfetto.webp b/engine_details/development/debugging/profiling/img/cpp_profiler_perfetto.webp new file mode 100644 index 00000000000..cf653cf7cfd Binary files /dev/null and b/engine_details/development/debugging/profiling/img/cpp_profiler_perfetto.webp differ diff --git a/engine_details/development/debugging/img/cpp_profiler_time_profiler.png b/engine_details/development/debugging/profiling/img/cpp_profiler_time_profiler.png similarity index 100% rename from engine_details/development/debugging/img/cpp_profiler_time_profiler.png rename to engine_details/development/debugging/profiling/img/cpp_profiler_time_profiler.png diff --git a/engine_details/development/debugging/img/cpp_profiler_time_profiler_record.png b/engine_details/development/debugging/profiling/img/cpp_profiler_time_profiler_record.png similarity index 100% rename from engine_details/development/debugging/img/cpp_profiler_time_profiler_record.png rename to engine_details/development/debugging/profiling/img/cpp_profiler_time_profiler_record.png diff --git a/engine_details/development/debugging/img/cpp_profiler_time_profiler_result.png b/engine_details/development/debugging/profiling/img/cpp_profiler_time_profiler_result.png similarity index 100% rename from engine_details/development/debugging/img/cpp_profiler_time_profiler_result.png rename to engine_details/development/debugging/profiling/img/cpp_profiler_time_profiler_result.png diff --git a/engine_details/development/debugging/profiling/img/cpp_profiler_tracy_recording.webp b/engine_details/development/debugging/profiling/img/cpp_profiler_tracy_recording.webp new file mode 100644 index 00000000000..39d093f505b Binary files /dev/null and b/engine_details/development/debugging/profiling/img/cpp_profiler_tracy_recording.webp differ diff --git a/engine_details/development/debugging/profiling/img/cpp_profiler_tracy_start.webp b/engine_details/development/debugging/profiling/img/cpp_profiler_tracy_start.webp new file mode 100644 index 00000000000..78ce73c1dbd Binary files /dev/null and b/engine_details/development/debugging/profiling/img/cpp_profiler_tracy_start.webp differ diff --git a/engine_details/development/debugging/img/cpp_profiler_verysleepy_results_filtered.png b/engine_details/development/debugging/profiling/img/cpp_profiler_verysleepy_results_filtered.png similarity index 100% rename from engine_details/development/debugging/img/cpp_profiler_verysleepy_results_filtered.png rename to engine_details/development/debugging/profiling/img/cpp_profiler_verysleepy_results_filtered.png diff --git a/engine_details/development/debugging/img/cpp_profiler_verysleepy_select_process.png b/engine_details/development/debugging/profiling/img/cpp_profiler_verysleepy_select_process.png similarity index 100% rename from engine_details/development/debugging/img/cpp_profiler_verysleepy_select_process.png rename to engine_details/development/debugging/profiling/img/cpp_profiler_verysleepy_select_process.png diff --git a/engine_details/development/debugging/img/cpp_profiler_xcode_menu.png b/engine_details/development/debugging/profiling/img/cpp_profiler_xcode_menu.png similarity index 100% rename from engine_details/development/debugging/img/cpp_profiler_xcode_menu.png rename to engine_details/development/debugging/profiling/img/cpp_profiler_xcode_menu.png diff --git a/engine_details/development/debugging/profiling/sampling_profilers.rst b/engine_details/development/debugging/profiling/sampling_profilers.rst new file mode 100644 index 00000000000..d1c4d88e002 --- /dev/null +++ b/engine_details/development/debugging/profiling/sampling_profilers.rst @@ -0,0 +1,152 @@ +.. _doc_sampling_profilers: + +Sampling profilers +================== + +Recommended profilers +--------------------- + +- `VerySleepy `__ (Windows only) +- `HotSpot `__ (Linux only) +- `Xcode Instruments `__ (macOS only) + +These profilers may not be the most powerful or flexible options, but their +standalone operation and limited feature set tends to make them easier to use. + +Setting up Godot +---------------- + +To get useful profiling information, it is **absolutely required** to use a Godot +build that includes debugging symbols. Official binaries do not include debugging +symbols, since these would make the download size significantly larger. + +To get profiling data that best matches the production environment (but with debugging symbols), +you should compile binaries with the ``production=yes debug_symbols=yes`` SCons options. + +It is possible to run a profiler on less optimized builds (e.g. ``target=template_debug`` without LTO), +but results will naturally be less representative of real world conditions. + +.. warning:: + + Do *not* strip debugging symbols on the binaries using the ``strip`` command + after compiling the binaries. Otherwise, you will no longer get useful + profiling information when running a profiler. + +Benchmarking startup/shutdown times +----------------------------------- + +If you're looking into optimizing Godot's startup/shutdown performance, +you can tell the profiler to use the ``--quit`` command line option on the Godot binary. +This will exit Godot just after it's done starting. +The ``--quit`` option works with ``--editor``, ``--project-manager``, and +``--path `` (which runs a project directly). + +.. seealso:: + + See :ref:`doc_command_line_tutorial` for more command line arguments + supported by Godot. + +Profiler-specific instructions +------------------------------ + +VerySleepy +~~~~~~~~~~ + +- Start the Godot editor or your project first. + If you start the Project Manager, make sure to edit or run a project first. + Otherwise, the profiler will not track the child process since the Project Manager + will spawn a child process for every project edited or run. +- Open VerySleepy and select the Godot executable in the list of processes on the left: + +.. image:: img/cpp_profiler_verysleepy_select_process.png + +- Click the **Profile All** button on the right to start profiling. +- Perform the actions you wish to profile in the editor or project. When you're done, click **Stop** (*not* Abort). +- Wait for the results window to appear. +- Once the results window appears, filter the view to remove external modules (such as the graphics driver). + You can filter by module by finding a line whose **Module** matches the Godot + executable name, right-clicking that line then choosing + **Filter Module to ** in the dropdown that appears. +- Your results window should now look something like this: + +.. image:: img/cpp_profiler_verysleepy_results_filtered.png + +HotSpot +~~~~~~~ + +- Open HotSpot. Click **Record Data**: + +.. image:: img/cpp_profiler_hotspot_welcome.png + +- In the next window, specify the path to the Godot binary that includes debug symbols. +- Specify command line arguments to run a specific project, with or without the editor. +- The path to the working directory can be anything if an absolute path is used + for the ``--path`` command line argument. Otherwise, it must be set so that + the relative path to the project is valid. +- Make sure **Elevate Privileges** is checked if you have administrative privileges. + While not essential for profiling Godot, this will ensure all events can be captured. + Otherwise, some events may be missing from the capture. + Your settings should now look something like this: + +.. image:: img/cpp_profiler_hotspot_record.png + +- Click **Start Recording** and perform the actions you wish to profile in the editor/project. +- Quit the editor/project normally or use the **Stop Profiling** button in HotSpot + to stop profiling early. Stopping profiling early can result in cleaner profiles + if you're not interested in the engine's shutdown procedure. +- Click **View Results** and wait for the profiling visualization to be generated: + +.. image:: img/cpp_profiler_hotspot_view_results.png + +- Use the tabs at the top to navigate between the different views. These views + show the same data, but in different ways. The **Flame Graph** tab is a good + way to see which functions take up the most time at a glance. These functions + are therefore the most important ones to optimize, since optimizing them will + improve performance the most. +- At the bottom of all tabs except **Summary**, you will also see a list of CPU threads + started by the engine along with the CPU utilization for each thread. + This lets you see threads that can be a bottleneck at a given point in time. + +.. image:: img/cpp_profiler_hotspot_flame_graph.png + +.. note:: + + If you don't want the startup procedure to be included in the profile, you + can also attach HotSpot to a running process by clicking **Record Data** + then setting the **Launch Application** dropdown option to **Attach To + Process(es)**. + + This process attachment-based workflow is similar to the one used by VerySleepy. + +Xcode Instruments +~~~~~~~~~~~~~~~~~ + +- Open Xcode. Select **Open Developer Tool** - **Instruments** from the **Xcode** app menu: +- Double-click on **Time Profiler** in the **Instruments** window: + +.. image:: img/cpp_profiler_xcode_menu.png + +- In the Time Profiler window, click on the **Target** menu, select **Choose target...** + and specify the path to the Godot binary, command line arguments, and environment variables + in the next window. + +.. image:: img/cpp_profiler_time_profiler.png + +- You can also attach the Time Profiler to a running process by selecting it from the **Target** + menu. + +- Click the **Start an immediate mode recording** button to start profiling. + +.. image:: img/cpp_profiler_time_profiler_record.png + +- Perform the actions you wish to profile in the editor or project. When you're done, + click the **Stop** button. + +- Wait for the results to appear. +- At the bottom of the window you will see a call tree for all CPU threads started, and + the **Heaviest Stack Trace** overview. +- Select **Hide system libraries** in the **Call Tree** menu (at the bottom of the window) to + remove external modules. +- You can use the timeline at the top of the window to display details for the specific time period. + +.. image:: img/cpp_profiler_time_profiler_result.png diff --git a/engine_details/development/debugging/profiling/tracing_profilers.rst b/engine_details/development/debugging/profiling/tracing_profilers.rst new file mode 100644 index 00000000000..6785c9e18df --- /dev/null +++ b/engine_details/development/debugging/profiling/tracing_profilers.rst @@ -0,0 +1,227 @@ +.. _doc_tracing_profilers: + +Tracing Profilers +================= + +Godot currently supports two tracing profilers: +`Tracy `__ and `Perfetto `__. + +In order to use either of them, you'll need to build the engine from source. +If you've never done this before, please read +:ref:`these docs ` for the platform you want to profile on. +You'll need to perform the same steps here, but with the addition of a single +extra argument for ``scons``. + +.. _doc_tracy_profiler: + +Tracy for Windows, Linux, and macOS +----------------------------------- + +Tracy is an Open Source profiler that runs on a wide variety of platforms, +including Windows, Linux, and macOS. While it is primarily a tracing profiler, +it can also periodically sample data like a +:ref:`sampling profiler `, giving some of the benefits +of both approaches. + +Build Godot with Tracy support +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +First, clone the latest version of the Tracy source code ("0.13.0" at the +time of writing) using Git: + +.. code-block:: shell + + git clone -b v0.13.0 --single-branch https://github.com/wolfpld/tracy.git + +This will create a ``tracy`` directory - you can place this anywhere. + +Next, build the release templates for your platform using ``scons``, but adding +the ``profiler_path=path/to/tracy`` argument with the real path to the ``tracy`` +directory, as well as ``debug_symbols=yes`` to allow Tracy's sampling features +to work. + +.. note:: + + You don't have to build release templates, you could also build debug + templates, or even the editor. However, it's generally recommended to + profile release templates, because that is the version your players will + use, and it will perform differently than other types of builds. + +For example, to build release templates for Windows: + +.. code-block:: shell + + scons platform=windows target=template_release debug_symbols=yes profiler_path=path/to/tracy + +Get the Tracy "server" +~~~~~~~~~~~~~~~~~~~~~~ + +In Tracy terminology, the application you are profiling is the "client", and +the one receiving the data is the "server". + +If you are on Windows, you can download a pre-built ``tracy-profiler.exe`` +from the Tracy `releases page `_. + +However, if you're on Linux or macOS, you'll either need to find a pre-built +binary from a package manager (like ``brew`` or ``nix``), or build it from +source yourself. + +.. note:: + + If you do use a pre-built binary, be sure to use the same version that + you used when building Godot. + +Build the Tracy server from source +++++++++++++++++++++++++++++++++++ + +The full details can be found in the +`Tracy manual `_, +but here is the TL;DR: + +.. code-block:: shell + + # On Linux, Tracy uses Wayland by default, so if you use X11 add -DLEGACY=1 + cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release + cmake --build profiler/build --config Release --parallel + +Record a trace +~~~~~~~~~~~~~~ + +Launch the Tracy server - you'll see something like this: + +.. image:: img/cpp_profiler_tracy_start.webp + +If you press "Connect" now, you can profile the launch of Godot. However, +if you want to profile something specific (for example, a part of your game +that is exhibiting performance issues), wait before pressing the button. + +Now, export your game using the release templates you built above, and run it. +As soon as both are running, and you have pressed the "Connect" button in +Tracy, you'll see data coming in: + +.. image:: img/cpp_profiler_tracy_recording.webp + +When you think you've gathered enough data, press the "Stop" button. If you +clicked somewhere and the box with the "Stop" button disappeared, you can +click the top-left most icon to bring it back. + +Examining the trace +~~~~~~~~~~~~~~~~~~~ + +Here are some of the basic controls: + +- Zoom in/out with the mouse wheel +- Right click and drag to move forward/backward on the timeline +- In the top bar, click the left and right arrow buttons by "Frames" to move a single frame on the timeline + +To learn more, see the +`Tracy manual `_. + +Perfetto for Android +-------------------- + +Perfetto is the default tracing system for Android. In fact, its system tracing +service has been built into the platform since Android 9. + +Build Godot with Perfetto support +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +First, clone the latest version of the Perfetto source code ("53.0" at the +time of writing) using Git: + +.. code-block:: shell + + git clone -b v53.0 --single-branch https://github.com/google/perfetto.git + +This will create a ``perfetto`` directory - you can place this anywhere. + +Next, build the Android debug or release templates for your architecture using +``scons`` (per :ref:`Compiling for Android `), but +adding the ``profiler_path=path/to/perfetto`` argument with the real path to +the ``perfetto`` directory. + +.. note:: + + It's generally recommended to profile release templates, because that is + the version your players will use, and it will perform differently than + other types of builds. However, in the case of Android, it can sometimes + be useful to use debug templates, because Godot can only do remote + debugging of games exported from debug templates. + +For example, to build the release templates for arm64: + +.. code-block:: shell + + scons platform=android target=template_release arch=arm64 generate_android_binaries=yes profiler_path=path/to/perfetto + +Configuration +~~~~~~~~~~~~~ + +Perfetto requires a configuration file to tell it which events to track. + +Create a file called ``godot.config`` inside of the ``perfetto`` directory +with this content: + +.. code-block:: text + + # Trace for 10 seconds. + duration_ms: 10000 + + buffers { + size_kb: 32768 + fill_policy: RING_BUFFER + } + + # Write to file once every second to prevent overflowing the buffer. + write_into_file: true + file_write_period_ms: 1000 + + # Track events in the "godot" category. + data_sources { + config { + name: "track_event" + track_event_config { + enabled_categories: "godot" + } + } + } + +Record a trace +~~~~~~~~~~~~~~ + +Finally, launch your game on an Android device using the export templates you +built earlier. + +When you're ready to record a trace (for example, when you've hit the part of +your game that is exhibiting performance issues), you can use this script that +comes with the Perfetto source code: + +.. code-block:: shell + + cd perfetto + ./tools/record_android_trace -c godot.config + +This will record for 10 seconds (per the configuration), or until you press +:kbd:`Ctrl + C`. + +Examining the trace +~~~~~~~~~~~~~~~~~~~ + +As soon as that script exits, it will launch the Perfetto UI in a web browser. + +To see the Godot events, expand the row for your application by clicking on its +Android "Unique Name" (Perfetto will also include some events from system +services in the trace). + +.. image:: img/cpp_profiler_perfetto.webp + +Then you can use the ``WASD`` keys to navigate the graph: + +- Press :kbd:`A` or :kbd:`D` to navigate forward or backward along the timeline +- Press :kbd:`W` or :kbd:`S` to zoom in or out + +You'll probably need to zoom a bit before you're able to see the individual +events from Godot. + +To learn more, see the +`Perfetto UI documentation `_. diff --git a/engine_details/development/debugging/using_cpp_profilers.rst b/engine_details/development/debugging/using_cpp_profilers.rst index df51becbbe1..6c87784fd19 100644 --- a/engine_details/development/debugging/using_cpp_profilers.rst +++ b/engine_details/development/debugging/using_cpp_profilers.rst @@ -12,150 +12,28 @@ To this end, profilers are useful tools. but using C++ profiler may be useful in cases where the GDScript profiler is not accurate enough or is missing information due to bugs in the profiler. -Recommended profilers ---------------------- +There are two main types of profilers: sampling profilers and tracing profilers. -- `VerySleepy `__ (Windows only) -- `HotSpot `__ (Linux only) -- `Xcode Instruments `__ (macOS only) +Sampling profilers periodically interrupt the running program and take a "sample", +which records which functions are running. Using this information, the profiler +estimates which functions the program spent the most time in. -These profilers may not be the most powerful or flexible options, but their -standalone operation and limited feature set tends to make them easier to use. +Tracing profilers work by recording application-specific events (such as the +start and end of a single frame), producing a log called a "trace". The profiler +can use the trace to produce a graph showing an accurate high-level timeline of +what happened. However, any code that is not explicitly instrumented will not +appear in a tracing profiler's timeline! -Setting up Godot ----------------- +Godot supports both sampling profilers and tracing profilers, and already +includes the logging code for common Godot events for use with a tracing profiler! -To get useful profiling information, it is **absolutely required** to use a Godot -build that includes debugging symbols. Official binaries do not include debugging -symbols, since these would make the download size significantly larger. +Different problems may be easier to debug with one kind of profiler over the other, +but it's difficult to provide a set of rules for which to use. Give both a try, +and see what you can learn from them! -To get profiling data that best matches the production environment (but with debugging symbols), -you should compile binaries with the ``production=yes debug_symbols=yes`` SCons options. +.. toctree:: + :maxdepth: 1 + :name: toc-devel-using-cpp-profilers -It is possible to run a profiler on less optimized builds (e.g. ``target=template_debug`` without LTO), -but results will naturally be less representative of real world conditions. - -.. warning:: - - Do *not* strip debugging symbols on the binaries using the ``strip`` command - after compiling the binaries. Otherwise, you will no longer get useful - profiling information when running a profiler. - -Benchmarking startup/shutdown times ------------------------------------ - -If you're looking into optimizing Godot's startup/shutdown performance, -you can tell the profiler to use the ``--quit`` command line option on the Godot binary. -This will exit Godot just after it finished starting. -The ``--quit`` option works with ``--editor``, ``--project-manager`` or -``--path `` (which runs a project directly). - -.. seealso:: - - See :ref:`doc_command_line_tutorial` for more command line arguments - supported by Godot. - -Profiler-specific instructions ------------------------------- - -VerySleepy -~~~~~~~~~~ - -- Start the Godot editor or your project first. - If you start the Project Manager, make sure to edit or run a project first. - Otherwise, the profiler will not track the child process since the Project Manager - will spawn a child process for every project edited or run. -- Open VerySleepy and select the Godot executable in the list of processes on the left: - -.. image:: img/cpp_profiler_verysleepy_select_process.png - -- Click the **Profile All** button on the right to start profiling. -- Perform the actions you wish to profile in the editor or project. When you're done, click **Stop** (*not* Abort). -- Wait for the results window to appear. -- Once the results window appears, filter the view to remove external modules (such as the graphics driver). - You can filter by module by finding a line whose **Module** matches the Godot - executable name, right-clicking that line then choosing - **Filter Module to ** in the dropdown that appears. -- Your results window should now look something like this: - -.. image:: img/cpp_profiler_verysleepy_results_filtered.png - -HotSpot -~~~~~~~ - -- Open HotSpot. Click **Record Data**: - -.. image:: img/cpp_profiler_hotspot_welcome.png - -- In the next window, specify the path to the Godot binary that includes debug symbols. -- Specify command line arguments to run a specific project, with or without the editor. -- The path to the working directory can be anything if an absolute path is used - for the ``--path`` command line argument. Otherwise, it must be set to that - the relative path to the project is valid. -- Make sure **Elevate Privileges** is checked if you have administrative privileges. - While not essential for profiling Godot, this will ensure all events can be captured. - Otherwise, some events may be missing in the capture. - Your settings should now look something like this: - -.. image:: img/cpp_profiler_hotspot_record.png - -- Click **Start Recording** and perform the actions you wish to profile in the editor/project. -- Quit the editor/project normally or use the **Stop Profiling** button in HotSpot - to stop profiling early. Stopping profiling early can result in cleaner profiles - if you're not interested in the engine's quit procedure. -- Click **View Results** and wait for the profiling visualization to be generated: - -.. image:: img/cpp_profiler_hotspot_view_results.png - -- Use the tabs at the top to navigate between the different views. These views - show the same data, but in different ways. The **Flame Graph** tab is a good - way to see which functions take up the most time at a glance. These functions - are therefore the most important ones to optimize, since optimizing them will - improve performance the most. -- At the bottom of all tabs except **Summary**, you will also see a list of CPU threads - started by the engine among with the CPU utilization for each thread. - This lets you see threads that can be a bottleneck at a given point in time. - -.. image:: img/cpp_profiler_hotspot_flame_graph.png - -.. note:: - - If you don't want the startup procedure to be included in the profile, you - can also attach HotSpot to a running process by clicking **Record Data** - then setting the **Launch Application** dropdown option to **Attach To - Process(es)**. - - This process attachment-based workflow is similar to the one used by VerySleepy. - -Xcode Instruments -~~~~~~~~~~~~~~~~~ - -- Open Xcode. Select **Open Developer Tool** - **Instruments** from the **Xcode** app menu: -- Double-click on **Time Profiler** in the **Instruments** window: - -.. image:: img/cpp_profiler_xcode_menu.png - -- In the Time Profiler window, click on the **Target** menu, select **Choose target...** - and specify the path to the Godot binary, command line arguments and environment variables - in the next window. - -.. image:: img/cpp_profiler_time_profiler.png - -- You can also attach the Time Profiler to a running process by selecting it from the **Target** - menu. - -- Click the **Start an immediate mode recording** button to start profiling. - -.. image:: img/cpp_profiler_time_profiler_record.png - -- Perform the actions you wish to profile in the editor or project. When you're done, - click the **Stop** button. - -- Wait for the results to appear. -- At the bottom of the window you will see a call tree for all CPU threads started, and - the **Heaviest Stack Trace** overview. -- Select **Hide system libraries** in the **Call Tree** menu (at the bottom of window) to - remove external modules. -- You can use the timeline at the top of the window to display details for the specific time period. - -.. image:: img/cpp_profiler_time_profiler_result.png + profiling/sampling_profilers + profiling/tracing_profilers