godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Add scope profiling methods to profile custom blocks of code #3361

Open ghsoares opened 3 years ago

ghsoares commented 3 years ago

Describe the project you are working on

A sandboarding runner with procedural terrain.

Describe the problem or limitation you are having in your project

I'm creating a procedural terrain for my runner game, where it generates a new mesh every time that a chunk LOD changes, it impacts the performance of my game so I want to profile where in my code is the bottleneck. In gdscript is easy because the profiler automatically profiles every function call, so I can just check the desired function to be profiled and the graph shows the frame time impact by this function. Now, in C# Godot don't profile script function calls so you rely on C#'s classes for profiling, like Stopwatch, but is not like the Godot's built-in profiler.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

As I assume that injecting profiling functions into every C# function is hard, my proposal is the ability to provide a scope to profile inside the code manually, it would work for C# and GDScript. You would call a function to start a named scope to profile and another function to end the named scope, every frame the function calls are accumulated and displayed on the Godot's Debugger->Profiler.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

I don't know which singleton is best to have these functions, but assuming that they are on a new singleton called Profiler, you could call inside any GDScript:

func _expensive_function() -> void:
    Profiler.start_scope("Expensive Function")
    var j := 0.0
    for i in range(100000000):
        j = sqrt(float(i))
    Profiler.end_scope("Expensive Function")

func _process(delta: float) -> void:
    for i in range(6):
        _expensive_function()

C#'s version:

private void ExpensiveFunction()
{
    Profiler.StartScope("Expensive Function");
    float j = 0f;
    for (int i = 0; i < 100000000; i++)
    {
        j = Mathf.Sqrt((float)i);
    }
    Profiler.EndScope("Expensive Function");
}

public override void _Process(float delta)
{
    for (int i = 0; i < 6; i++)
    {
        ExpensiveFunction();
    }
}

In this example, _expensive_function is called 6 times a frame, so the function would accumulate the named scope frame time in a frame and display the total frame time spent in all the function calls. You don't need to provide the function name, also you can have multiple scopes inside a function.

You must ensure that you end a scope, else it would throw a error next time you start without ending it.

If this enhancement will not be used often, can it be worked around with a few lines of script?

It would require a custom profiler tool that would display in-game, as there is no interface between the scripts and the editor profiler.

Is there a reason why this should be core and not an add-on in the asset library?

It makes easier to deep profile scripts for GDScript and enables built-in profiling for C#, as there is no way to profile C# scripts with Godot's built-ins.

Calinou commented 3 years ago

Godot supports custom performance monitors in the master branch, so you should be able to implement this with a few lines of code.

To manually measure the time taken by the execution of a block of code, see CPU optimization in the documentation.

ghsoares commented 3 years ago

@Calinou This is really useful, but I think that these custom performance monitors would only work for a entire function, not a individual scope. My proposal enables a more deep profiling by providing a custom scope to be profiled, so you can track easily an individual piece of code that slows down an entire function

kisg commented 3 years ago

Just a quick FYI, I am working on a proposal to integrate Perfetto (https://perfetto.dev) into Godot Core. I already have a prototype running on Godot 3.x branch, and it supports what you are looking for: low overhead scope based profiling. It currently only has a C++ API, but it should be relatively straightforward to wrap it into a C API that can be then integrated with C#.

Actually Google is already working on the C API version: https://android-review.googlesource.com/c/platform/external/perfetto/+/1831574