\\/__,_ / \/____//\ \_\ \\/__/\/_/ \/____/ \/_/\/_/<br>/\___/ \ \____/<br>\/__/ \/___/
Powered by Hydejack v6.6.1<br>-->We Should Use Instrumented Profiling Scopes More · Mathieu Ropert Jump to: Menu
I have made an entire talk about profiling. Still, I keep running across projects that don’t use profilers much or at all. Or even more commonly, they do use profilers but do not know they can enrich their projects with profiler markers that would make captures more valuable and much easier to parse. Let’s fix that!Two and a half profiler types<br>There’s many profilers out there, often split based on which form of profiling capture they rely upon:Sampling, which periodically pauses the program, records the stack trace of every threads, then continues. By doing this often enough (at least 1kHz, preferably more), we can build a breakdown of where on average does our capture spends CPU time. This is the default capture mode when using Instruments, vTune, Superluminal, Visual Studio or VerySleepy).Instrumented, where the program itself records time slices when markers are invoked. This requires code hooked up to the profiler to be added in the project and only markers present when the project was compiled will be visible, nothing else. This is the default capture of profilers included in game engines such as Unity or Unreal, as well most “game-oriented” profilers like Optick, Tracy and PIX.Ideally you want a profiler that can do both at the same time, and well. Which usually means using the ones who are built for instrumentation first and then added sampling on top1. The idea being, they will display an instrumentation-driven flame chart, on which you can click on any individual marker to get a sampling frame graph2 of all the stacks that fell under it.What you get in an capture<br>In the capture above you can see the per frame time at the top, then the timeline of each frame in the middle and finally the flame graph under the selected element at the bottom right. As we explained before the instrumented tags come from what I added to the codebase3, while the sampling tags are extracted from the stack trace and the debug symbols, giving us an insight into which low level Windows APIs are being used (and in our case, taking way too much frame time).That way we get the best of both worlds. The instrumented flame chart gives us an easy way to spot outliers and most commonly offending parts, while sampling gives us an immediate measured breakdown without needing to add more instrumentation scopes (and recompiling).Getting started<br>The first question is: are you using a big game engine like Unity or Unreal? If so, there’s already something there for you.Unreal<br>In Unreal 5 it’s called Unreal Insights and it’s already full of information even if you use it out of the box. Every engine thread is already registered, most important engine functions already have profiling scopes, as well as the entry point of each blueprint and the tick function of every AActor in your game. That should be enough as a starting point to give you a rough picture of what’s happening in your tick.But of course, you will want to add your own. Especially if you implement custom ticking objects that do a lot of work and could use a breakdown under the basic FTickableGameObject.#include "ProfilingDebugging/CpuProfilerTrace.h"
struct CustomManager : FTickableGameObject<br>TStatId GetStatId() const override<br>// Tickables don't have a nice label by default<br>// Override to supply one<br>RETURN_QUICK_DECLARE_CYCLE_STAT(CustomManager, STATGROUP_Tickables);
// Already scoped with the label given by GetStatId, but children aren't<br>void Tick(float DeltaTime) override<br>Foo();<br>Bar();<br>Bazz();
void Foo()<br>TRACE_CPUPROFILER_EVENT_SCOPE_STR("Foo");<br>// ...
void Bar()<br>TRACE_CPUPROFILER_EVENT_SCOPE_STR("Bar");<br>// ...
// And so on...<br>} ;
Unity<br>Similar to Unreal, Unity will add tags that will appear in the Unity Profiler for engine side operations, MonoBehaviour updates, coroutines, Entities systems and GC allocs.That’s already quite a bit, but like with Unreal when turning MonoBehaviour into a manager class with complex Update() it usually doesn’t tell enough to give the full picture.There is, of course, an API to add your own profiler markers:using Unity.Profiling;
public class CustomManager : MonoBehaviour<br>// Profiler marker are expensive to create, cache them in the class<br>static readonly ProfilerMarker s_FooPerfMarker = new ProfilerMarker("Foo");<br>static readonly ProfilerMarker s_BarPerfMarker = new ProfilerMarker(ProfilerCategory.Ai,<br>"Bar");
public void Update()<br>Foo();<br>Bar();<br>Bazz();
private void Foo()<br>s_FooPerfMarker.Begin();<br>// ...<br>s_FooPerfMarker.End();
private void Bar()<br>// RAII-ish alternative<br>using (s_BarPerfMarker.Auto())<br>// ...
Custom engines<br>On custom engines, you will have to rely on a 3rd party profiler. I will use Optick for the rest of this section but others are very similar. I still prefer it in my personal projects despite the fact that the project seems...