Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Der Profiler

Sie starten Ihr Spiel von Godot aus und spielen herum. Es macht Spaß, die Features werden immer vollständiger, und Sie haben das Gefühl, dass es kurz vor der Veröffentlichung steht.

Doch dann öffnen Sie den Fertigkeitenbaum, und er kommt zum Stillstand, weil etwas in Ihrem Code hängen bleibt. Es ist inakzeptabel, den Fertigkeitenbaum wie eine Diashow vorbeiziehen zu sehen. Was ist schief gelaufen? Liegt es an der Positionierung der Elemente im Fertigkeitenbaum, an der Benutzeroberfläche oder am Rendering?

Sie könnten versuchen, alles zu optimieren und das Spiel wiederholt laufen zu lassen, aber Sie können auch schlauer vorgehen und die Möglichkeiten eingrenzen. Hier kommt der Profiler von Godot ins Spiel.

Ein Überblick über den Profiler

Sie können den Profiler öffnen, indem Sie das Fenster Debugger öffnen und auf den Profiler-Tab klicken.

../../../_images/profiler.png

Der Profiler von Godot wird nicht automatisch ausgeführt, da die Profilerstellung Performance-intensiv ist. Er muss ständig alles, was im Spiel passiert, messen und an den Debugger zurückmelden, daher ist er standardmäßig deaktiviert.

Um mit dem Profiling zu beginnen, klicken Sie auf Start-Button oben links. Starten Sie Ihr Spiel und die Daten werden angezeigt. Sie können das Profiling auch jederzeit vor oder während des Spiels starten, je nachdem, was Sie möchten.

Bemerkung

Der Profiler unterstützt derzeit keine C#-Skripte. C#-Skripte können mit JetBrains Rider und JetBrains dotTrace mit dem Godot-Support-Plugin profiliert werden.

Sie können die Daten jederzeit löschen, indem Sie auf den Löschen-Button klicken. Verwenden Sie das Dropdown-Menü Messung, um die Art der Daten zu ändern, die Sie messen. Das Messungsfeld und das Diagramm werden entsprechend aktualisiert.

Die gemessenen Daten

Die Benutzeroberfläche des Profilers ist zweigeteilt. Auf der linken Seite befindet sich eine Liste der Funktionen und auf der rechten Seite das Performance-Diagramm.

Die wichtigsten Messungen sind Frame-Zeit, Physik-Frame, Leerlaufzeit und Physik-Zeit.

  • Die Frame-Zeit ist die Zeit, die Godot benötigt, um die gesamte Logik für ein Bild auszuführen, von der Physik bis zum Rendering.

  • Der Physik-Frame ist die Zeit, die Godot zwischen den Aktualisierungen der Physik zugewiesen hat. In einem idealen Szenario ist die Frame-Zeit, was auch immer Sie gewählt haben: Standardmäßig 16,66 Millisekunden, was 60 FPS entspricht. Es ist ein Bezugsrahmen, den Sie für alles andere um ihn herum verwenden können.

  • Die Leerlaufzeit ist die Zeit, die Godot brauchte, um andere Logik als die der Physik zu aktualisieren, z.B. Code, der sich in _process befindet, oder Timer und Kameras, die so eingestellt sind, dass sie bei Leerlauf aktualisiert werden.

  • Physikzeit ist die Zeit, die Godot für die Aktualisierung von Physikaufgaben wie _physics_process und eingebauten Nodes, die auf Physik eingestellt sind, benötigt hat.

Bemerkung

In Godot 3 umfasst Frame Time die Rendering-Zeit. Angenommen, Sie stellen eine mysteriöse Verzögerung in Ihrem Spiel fest, aber Ihre Physik und Skripte laufen alle schnell. Die Verzögerung könnte auf das Auftreten von Partikeln oder visuellen Effekten zurückzuführen sein!

Standardmäßig zeigt Godot Frame-Zeit und Physik-Zeit an. So erhalten Sie einen Überblick darüber, wie lange jedes Bild im Verhältnis zu den zugewiesenen gewünschten Physik-FPS dauert. Sie können die Funktionen ein- und ausschalten, indem Sie auf die Kontrollkästchen auf der linken Seite klicken. Nach und nach erscheinen weitere Funktionen wie Physik 2D, Physik und Audio, bevor Sie zu den Skriptfunktionen gelangen, wo Ihr Code erscheint.

Wenn Sie auf das Diagramm klicken, können Sie ändern, welche Bildinformationen auf der linken Seite angezeigt werden. Oben rechts befindet sich außerdem ein Frame-Zähler, mit dem Sie den betrachtete Frame manuell genauer einstellen können.

Umfang der Messung und Messfenster

Über das Dropdown-Menü Messung können Sie die angezeigte Messung ändern. Standardmäßig beginnt es mit Frame Time und listet die Zeit in Millisekunden auf, die zum Durchlaufen des Frames benötigt wird. Die Durchschnittszeit ist die durchschnittliche Zeit, die eine bestimmte Funktion benötigte, wenn sie mehr als einmal aufgerufen wurde. Eine Funktion, die beispielsweise fünfmal 0,05 Millisekunden für die Ausführung benötigte, sollte einen Durchschnitt von 0,01 Millisekunden ergeben.

Wenn die genaue Zählung der Millisekunden nicht wichtig ist und Sie den Anteil der Zeit im Verhältnis zum Rest des Frames sehen möchten, verwenden Sie die prozentuale Messung. Frame % ist relativ zu Frame-Zeit und Physics % ist relativ zu Physik-Zeit.

Die letzte Option ist der Umfang der Zeit. Inklusive misst die Zeit, die eine Funktion mit allen verschachtelten Funktionsaufrufen benötigt hat. Zum Beispiel:

../../../_images/split_curve.png

get_neighbors, find_nearest_neighbor und move_subject brauchten alle sehr viel Zeit. Man könnte meinen, dass dies daran liegt, dass alle drei langsam sind.

Bei der Änderung auf Self misst Godot jedoch die im Funktionsrumpf verbrachte Zeit, ohne die Funktionsaufrufe zu berücksichtigen, die er selbst vorgenommen hat.

../../../_images/self_curve.png

Sie können sehen, dass get_neighbors und move_subject viel von ihrer Bedeutung verloren haben. Das bedeutet, dass get_neighbors und move_subject mehr Zeit damit verbracht haben, auf die Beendigung eines anderen Funktionsaufrufs zu warten, als nicht, und find_nearest_neighbor ist tatsächlich langsam.

Debugging von langsamem Code mit dem Profiler

Um langsamen Code mit dem Profiler zu finden, müssen Sie Ihr Spiel laufen lassen und das Performance-Diagramm beobachten, während es gezeichnet wird. Wenn eine inakzeptable Spitze in der Frame-Zeit auftritt, können Sie auf das Diagramm klicken, um Ihr Spiel anzuhalten und den _Frame #_ zum Beginn der Spitze einzugrenzen. Möglicherweise müssen Sie zwischen Frames und Funktionen hin- und herspringen, um die Ursache zu finden.

Aktivieren Sie unter den Skriptfunktionen die Kontrollkästchen für einige Funktionen, um herauszufinden, welche davon Zeit benötigen. Dies sind die Funktionen, die Sie überprüfen und optimieren müssen.

Manuelles Messen in Mikrosekunden

Wenn Ihre Funktion komplex ist, kann es schwierig sein, herauszufinden, welcher Teil optimiert werden muss. Ist es Ihre Mathematik oder die Art und Weise, wie Sie auf andere Daten zugreifen, mit denen Sie die Mathematik durchführen? Ist es die for-Schleife? Die if-Anweisungen?

Sie können die Messung eingrenzen, indem Sie manuell die Ticks zählen, während der Code mit einigen temporären Funktionen ausgeführt wird. Die beiden Funktionen sind Teil des Objekts der Klasse Time. Sie heißen get_ticks_msec und get_ticks_usec. Die erste misst in Millisekunden (1.000 pro Sekunde), die zweite in Mikrosekunden (1.000.000 pro Sekunde).

Beide geben die Zeit zurück, die seit dem Start der Spiel-Engine im jeweiligen Zeit-Frame vergangen ist.

Wenn Sie ein Codestück mit einem Start- und End-Zähler von Mikrosekunden versehen, ist die Differenz zwischen den beiden die Zeit, die für die Ausführung dieses Codestücks benötigt wurde.

# Measuring the time it takes for worker_function() to run
var start = Time.get_ticks_usec()
worker_function()
var end = Time.get_ticks_usec()
var worker_time = (end-start)/1000000.0

# Measuring the time spent running a calculation over each element of an array
start = Time.get_ticks_usec()
for calc in calculations:
    result = pow(2, calc.power) * calc.product
end = Time.get_ticks_usec()
var loop_time = (end-start)/1000000.0

print("Worker time: %s\nLoop time: %s" % [worker_time, loop_time])

Wenn Sie ein erfahrener Programmierer werden, wird diese Technik immer weniger notwendig. Man beginnt zu lernen, welche Teile eines laufenden Programms langsam sind. Das Wissen, dass Schleifen und Verzweigungen langsam sein können, kommt aus der Erfahrung, und man sammelt Erfahrung, indem man misst und recherchiert.

Aber mit dem Profiler und den Tick-Funktionen sollten Sie genug in der Hand haben, um herauszufinden, welche Teile Ihres Codes optimiert werden müssen.