Mehr Performance: VALORANTs globale Invalidierung

Wie das Leistungsteam von VALORANT die Performance deines Clients verbessert hat.

Hallo! Ich bin Aaron Cheney, Software Engineer im Leistungsteam von VALORANT. Stabile Performance ist eine wichtige Komponente von VALORANTs kompetitiver Integrität und unser Team überwacht, wartet und verbessert sowohl die Leistung des Servers als auch die Performance des Clients.

Heute gibt es Neuigkeiten zu einer Funktion, an der wir mehrere Monate lang gearbeitet haben: die globale Invalidierung. Bevor wir uns die Funktion im Detail ansehen, werfen wir zuerst einmal einen Blick auf die Performance des Clients seit Patch 4.03.

Spoiler: Da hat sich einiges getan.

AskVal_March22_Global_Invalidation_Graph_3.jpg

Die globale Invalidierung hatte für einen großen Teil unserer Spieler deutliche Verbesserungen zur Folge. Es handelt sich hier um die größte Leistungsverbesserung des Clients seit der Veröffentlichung von VALORANT.

Auch wenn diese Diagramme schon ziemlich gut aussehen – und uns die Ergebnisse begeistern –, sollte man die Hintergründe verstehen. Wir arbeiten mit großen, komplexen Datensätzen und um das Spielererlebnis zu verstehen, organisieren, filtern und kontrollieren wir sie. Um alle Zusammenhänge zu verstehen, musst du Folgendes bedenken:

  • Das Diagramm zeigt „Patch“ im Vergleich zur „durchschnittlichen Bildrate“; je höher die Zahlen, desto besser.
  • Jede Linie repräsentiert eine häufig genutzte Hardwarekonfiguration (Prozessor und Grafikkarte) in unserer Spielerschaft. Bei der Analyse von Leistungsdaten betrachten wir diese Konfigurationen als wichtigsten Faktor für die erwartete Performance. In diesen Diagrammen sind Rechner mit derselben Prozessor- und Grafikkartenkonfiguration zusammengefasst.
  • Die Datenproben stammen aus zwei Warteschlangen: ungewertet und gewertet. Da diese beiden Spielmodi am beliebtesten sind, investieren wir viel Zeit und Energie, um die Performance in diesen Bereichen zu verstehen und zu verbessern.
  • Matches, an denen nicht genau 10 Spieler teilnehmen, werden nicht gezählt. So verhindern wir, dass Ausreißer die Daten verzerren. (Matches mit weniger Teilnehmenden haben auch eine bessere Leistung.)

ZUSAMMENFASSUNG DER GLOBALEN INVALIDIERUNG

global-invalidation-summary-flow.jpg

Die globale Invalidierung sorgt für bis zu 15 % mehr Leistung bei Clients mit limitierendem Prozessor (allgemein Rechner der Mittel- bis High-End-Klasse). Diese Steigerungen sind das Ergebnis von monatelanger Arbeit in mehreren Teams. Unser Prozess zur Identifizierung optimierungsfähiger Bereiche im Spiel hat sich bewährt und das Risikomanagement währenddessen für ein stabiles Spielererlebnis gesorgt.

Wer davon profitiert, und realistische Erwartungen

Laut unserer Live-Messungen sorgt die globale Invalidierung für bis zu 15 % mehr Leistung bei Client-Konfigurationen mit limitierendem Prozessor (allgemein Rechner der Mittel- bis High-End-Klasse).

Der deutliche Aufwärtstrend in der Gesamtbetrachtung repräsentiert allerdings nicht das Spielgeschehen im Detail. Außerdem ist nicht gewährleistet, dass alle Rechner mit entsprechender Hardware auch von denselben Ergebnissen profitieren.

Das bedeutet, dass sich die grundlegende Leistung von VALORANT auf Rechnern mit limitierendem Prozessor allgemein verbessert hat. Allerdings hängt die Gesamtleistung deines Rechners von verschiedenen individuellen Faktoren ab.

DIE GLOBALE INVALIDIERUNG VERSTEHEN

Bevor wir uns einen Überblick über die globale Invalidierung verschaffen, müssen wir zuerst über Elemente der Benutzeroberfläche in der Unreal Engine sprechen.

Widgets und Baumstrukturen

Die Elemente der Benutzeroberfläche (auch bekannt als Widgets) werden mithilfe einer Baumstruktur aus kleineren Bausteinen zusammengesetzt. Die Baumstruktur entspricht dem Dateisystem auf deinem Computer. Ein Widget kann eine beliebige Anzahl an Kindern haben (wie auch ein Ordner eine beliebige Anzahl an Dateien enthalten kann).

Diese Bausteine kann man zu komplexen Widgets kombinieren. Unsere Munitionsanzeige besteht beispielsweise aus vielen Teilen und der Baum sieht folgendermaßen aus:

Screenshot_2022-03-07_at_16-30-57_PRF_-_Global_Invalidation_article.png

Zusammengenommen sehen die Bausteine für die Munitionsanzeige so aus:

AskVal_March22_Valorant_UI_Elements.jpg

(Die roten Umrisse sind hervorgehoben, um sie deutlich zu machen. In der Praxis würden sie sich überschneiden.)

Wenn sich ein oder mehrere Widgets in der Baumstruktur ändern, kann das mehrere andere Widgets beeinflussen. Wenn zum Beispiel ein Widget auf dem Bildschirm eine neue Position einnimmt, müssen alle untergeordneten Widgets auch eine neue Position berechnen. Diese Änderungen verwaltet ein System namens „Invalidierung“. Im nächsten Abschnitt sehen wir es uns genauer an.

Invalidierung

Invalidierung ist ein Mechanismus in der Unreal Engine, der meldet, wenn ein Widget sich verändert hat und aktualisiert werden muss.

Ein Widget muss aus verschiedenen Gründen invalidiert werden: Animationen, Farbe, Transparenz, Größe, Anordnung, Text, Bilder und viele weitere Eigenschaften können sich als Reaktion auf das Spielgeschehen ändern. Sobald diese Änderungen eintreten, wird das Widget „invalidiert“, es verliert also seine Gültigkeit und muss aktualisiert werden.

Allerdings ist dieser Prozess etwas komplizierter, da es verschiedene Arten von Invalidierung geben kann. Dazu gehören:

  • Anordnung – Wenn sich die Größe des Widgets ändert (sehr ressourcenintensiv).
  • Farbe – Wenn sich das Aussehen des Widgets, aber nicht die Größe geändert hat.
  • Anordnung der Kinder – Wenn sich die Anordnung der Widgets innerhalb eines Baumes geändert hat (betrifft auch die Anordnung und ist daher ressourcenintensiv).
  • Sichtbarkeit – Wenn sich die Sichtbarkeit eines Widgets ändert, es also entweder unsichtbar oder sichtbar wird (betrifft auch die Anordnung und ist daher ressourcenintensiv).

Diese Arten der Invalidierung geben an, welche Operationen zur korrekten Anzeige ausgeführt werden müssen.

Das Ganze wird noch komplizierter, wenn ein Widget von einem anderen abhängig ist. Widgets sind in Hierarchien organisiert und die Anordnung hängt von verschiedenen Faktoren ab. Wenn ein einzelnes Widget invalidiert wird, müssen möglicherweise auch mehrere abhängige Widgets invalidiert werden, bevor es neu angezeigt werden kann. Wenn beispielsweise mehrere Widgets in einer vertikalen Anordnung organisiert sind (wie im Fenster „Sozial“ mit der Freundesliste) und sich die Reihenfolge der Widgets ändert (wenn ein Freund online kommt), müssen alle Widgets innerhalb der vertikalen Anordnung aktualisiert werden.

In so einem System gibt es mehrere Vorgaben:

  • So wenig Widgets wie möglich invalidieren. Das verringert die Anzahl der Widgets, die aktualisiert werden müssen, bevor ein Element angezeigt werden kann.
  • Widgets nur wenn nötig invalidieren. Wird ein Widget unnötigerweise invalidiert, verschwendet man wertvolle Prozessorzyklen.
  • Das Ergebnis zwischenspeichern, wenn ein Widget nicht invalidiert wird, um es bei jedem Einzelbild schnell anzeigen zu können. Wenn sich nichts ändert, lassen sich Prozessorzyklen sparen.

Wir sollten jetzt eine Ahnung davon haben, wie Widgets aktualisiert werden und was eine Invalidierung auslösen kann. Als Nächstes sehen wir uns an, wie Entwickler die Theorie in der Praxis umsetzen.

Invalidierungsboxen

Die Unreal Engine stellt eine Komponente bereit – nämlich Invalidierungsboxen –, mit der sich mehrere Widgets gruppieren lassen. Widgets in einer Invalidierungsbox werden nicht vorgerendert, dargestellt und es wird kein Code für sie ausgeführt. Stattdessen werden die Ergebnisse in einem Vertex-Puffer zwischengespeichert.

Sobald ein Widget in der Invalidierungsbox invalidiert wird, werden zwischengespeicherte Daten gelöscht und die Widgets werden aktualisiert und neu dargestellt. Die Aktualisierung des Zwischenspeichers für ein Einzelbild ist zwar ressourcenintensiv, die Ergebnisse machen sich langfristig allerdings bezahlt.

Invalidierungsboxen waren extrem wichtig für die Leistung der Benutzeroberfläche in VALORANT, besonders kurz vor der Veröffentlichung. Aber sie sind nicht umsonst:

  • Entwickler müssen wissen, welche Widgets sich gut in einer Invalidierungsbox gruppieren lassen. Widgets, die sich regelmäßig aktualisieren, eignen sich nicht dafür.
  • Entwickler müssen Widgets manuell in einer Invalidierungsbox platzieren. Dieser Aufwand lohnt sich nicht für jedes Widget im Spiel, deshalb muss man wissen, welche Widgets sinnvoll in einer Invalidierungsbox aufgehoben sind.

Weitere Informationen zu Invalidierungsboxen findest du in der Dokumentation von Epic (in englischer Sprache).

Jetzt kennen wir den nötigen Kontext, um uns über die globale Invalidierung zu unterhalten.

Die globale Invalidierung betritt die Bühne

Bestimmt fragst du dich jetzt, warum man nicht einfach alle Elemente der Benutzeroberfläche in eine globale Invalidierungsbox packt. Und genau das tut die globale Invalidierung auch (zumindest so etwas in der Art).

Die globale Invalidierung soll die Leistung der Benutzeroberfläche im Spiel deutlich verbessern und gleichzeitig die nötige manuelle Arbeit von Entwicklern verringern, die Widgets in individuellen Invalidierungsboxen platzieren müssen. Problem gelöst!

Allerdings unterstützt die Unreal Engine 4.25 (die Version, die VALORANT verwendet) die globale Invalidierung nicht universell für alle Widget-Typen. Spätere Versionen der Engine haben Verbesserungen implementiert, doch die konnte VALORANT nicht sofort nutzen. Außerdem hatten wir nicht auf dem Schirm, wie deutlich die globale Invalidierung die Leistung von VALORANT beeinflussen würde.

Und hier ging unsere Arbeit los.

WARUM HABEN WIR DIESE ARBEIT AUF UNS GENOMMEN?

Ende Juli 2021 beschloss das Team, sich die globale Invalidierung in einem internen Testlauf anzusehen. Es wurden kleinere Änderungen vorgenommen, um ein paar Fehler zu beheben und den Testlauf erfolgreich durchzuführen. Allerdings war uns klar, dass es während des Testlaufs zu Fehlern kommen würde … und da lagen wir auch richtig.

Nach dem Testlauf hatten wir um die 20 Fehler gefunden – und das waren nur die offensichtlichen. Es warteten wahrscheinlich auch noch unauffällige, hinterhältige Fehler darauf, entdeckt zu werden. Ganz zu schweigen von mehreren Grenzfällen, die wir nicht gesondert getestet hatten.

Aber … sorgte die globale Invalidierung für eine verbesserte Leistung? Absolut.

Die Datenanalyse nach diesem Testlauf ergab, dass die Benutzeroberfläche jetzt ~35 % schneller lief. (Hinweis: Die Benutzeroberfläche ist nur ein Teil der Kosten für ein Einzelbild.)

Allerdings waren noch viele Fragen offen:

  • Wie lange würde es dauern, alle Fehler zu beheben?
  • Welche Teams sollten sich darum kümmern?
  • Sollten wir diese Arbeit vor allen anderen Vorhaben priorisieren? Um regelmäßig neue Inhalte abliefern zu können, sind unsere Kalender oft schon Monate im Voraus vollgeplant. Unerwartete Projekte, so interessant sie auch sein mögen, kriegt man da nur mit Mühe unter.
  • Werden die Leistungsvorteile weniger, wenn wir die Fehler beheben? Fehler lassen sich nur mit Änderungen am Code beheben, welche die Benutzeroberfläche potenziell wieder ressourcenintensiver machen können.
  • Wann haben wir Zeit dafür? Da wir wussten, dass die globale Invalidierung in späteren Versionen der Unreal Engine aktiv entwickelt wurde, mussten wir unseren eigenen Zeitplan abstimmen, um die Änderungen von Epic zu implementieren.

Letzten Endes sahen wir den Aufwand aus mehreren Gründen als lohnenswert an.

Implementierung in die Unreal Engine und Überlegungen hinsichtlich des Zeitplans

Unreal Engine 4.26 und 4.27 bieten zwar deutliche Fortschritte im Bereich der globalen Invalidierung, VALORANT implementiert neue Versionen allerdings mit Verzögerung. Wir sind nicht immer am „Puls der Zeit“, um Risiken zu vermeiden und unseren Spielern Stabilität zu garantieren.

Laut des damaligen Zeitplans wollten wir noch viele weitere Monate mit der Unreal Engine 4.25 arbeiten, sodass die Spieler erst in über einem Jahr von diesen Leistungsoptimierungen profitiert hätten. Das konnten wir nicht verantworten.

Weitere Details über die Philosophie hinter Unreal Engine-Upgrades für VALORANT findest du in diesem Twitter-Beitrag von VALORANTs Tech Lead Marcus Reid (in englischer Sprache).

Messbare Leistungssteigerungen

Die globale Invalidierung war in Sachen Leistungsoptimierung ziemlich einmalig, da sich ihr Wert messen ließ. Wir konnten die mögliche Leistungssteigerung in einem internen Testlauf feststellen und danach war unsere Strategie (größtenteils) klar.

Leistungsoptimierungen sind schwierig. Normalerweise verbessern kleine Änderungen die Leistung im Lauf der Zeit und eine einzige Änderung bietet nur in äußerst seltenen Fällen Leistungsgewinne im zweistelligen Bereich. Wir konnten diese Gelegenheit also unmöglich ungenutzt lassen.

Auch nach Abzug der Leistungsverluste aufgrund von Fehlerbehebungen konnten wir den Spielern mithilfe der globalen Invalidierung innerhalb eines angemessenen Zeitraums potenziell deutliche Verbesserungen bieten.

WIE HABEN WIR DAS ANGESTELLT?

Obwohl wir bereits Ende Juli 2021 die ersten Experimente mit der globalen Invalidierung durchgeführt hatten, begannen die wirklichen Arbeiten erst Ende September 2021.

Änderungen von Epic selektiv implementieren

Eine komplette Implementierung von Unreal Engine 4.26 und 4.27 stand zwar außer Frage, doch Epic hatte bereits aktiv an der globalen Invalidierung gearbeitet. Wir sahen uns also Tausende von Änderungen an und entschieden, welche wir für eine stabile, funktionstüchtige globale Invalidierung in unserer Version der Engine gebrauchen konnten.

Änderungen teilweise zu implementieren war eine echte Herausforderung. Wir wollten so wenige Kernfunktionen der Engine wie möglich modifizieren, um die Stabilität nicht zu beeinträchtigen, aber gleichzeitig die richtigen Änderungen von Epic einbauen. Die gesamten Arbeiten fanden isoliert von VALORANTs Hauptversion statt, um die anderen Entwickler nicht zu stören.

Nachdem wir die Änderungen von Epic selektiv in unsere Engine übernommen hatten, behoben wir im Laufe von mehreren Wochen so viele Fehler wie möglich. Gleichzeitig bereiteten wir die Einführung der globalen Invalidierung in die Hauptversion von VALORANT vor. Parallel dazu implementierten wir eine Schaltfläche, über die sich die Funktion schnell aktivieren und wieder ausschalten ließ (für den Fall, dass es zu einer Katastrophe kam).

Nachdem viele Fehler aus dem Weg geräumt und viele von Epics Änderungen für die Unreal Engine 4.26 und 4.27 eingebaut waren, fusionierten wir unsere isolierte Version wieder mit der Hauptversion.

Gemeinsamkeiten zwischen Fehlern finden

Obwohl viele der Fehler im Zusammenhang mit der globalen Invalidierung sich auf unterschiedliche Arten äußerten, war die Wurzel allen Übels oft ein einziges Problem. Diese Fehler hatten für uns oberste Priorität, da wir so mehrere Probleme mit einer einzigen Änderung beseitigen konnten. Eine Anpassung konnte zum Beispiel über 10 Fehler berichtigen, die über das Spiel verteilt waren. Die gründliche Analyse des grundlegenden Problems führte zu robusten Lösungen, die sowohl die Verlässlichkeit als auch die Stabilität der globalen Invalidierung verbesserten.

Fehler identifizieren, beheben, testen – und wieder von vorne

Die nächsten Wochen und Monate spielten sich nach folgendem Muster ab: Globale Invalidierung vor einem Testlauf aktivieren, eine Reihe Fehler finden, globale Invalidierung nach dem Testlauf deaktivieren und die Fehler beheben.

developer-bug-fix-flow.jpg


Mit jedem neuen Durchgang fanden wir weniger Fehler. Wir machten weiter, bis der ständige Strom an Fehlern schließlich nachließ und dann ganz versiegte.

Gegen Ende November 2021 hatten wir alle großen Probleme beseitigt und die globale Invalidierung war größtenteils stabil.

Nennenswerte Fehler
  • Astra lässt das Spiel abstürzen – Vorübergehend mussten sich Astra-Spieler mit Abstürzen herumschlagen. Dieser Fehler ließ sich nach der Implementierung der Änderungen von Epic beheben.
  • Absturz bei Mehrfachvererbung – Mehrfachvererbung in C++ ist ein kniffliges Thema. Ohne zu tief in die Materie einzusteigen: Die Destruktoren einer Klasse wurden nicht in der richtigen Reihenfolge ausgeführt, was zu einem Absturz führte. Wir mussten lediglich zwei Zeilen Code vertauschen, um die Vererbungsreihenfolge zu ändern und das Problem zu lösen. Weitere Informationen zu Mehrfachvererbung findest du auf dieser Seite (in englischer Sprache).
  • Pausenlos wiederholtes Audio der Chatleiste – Wenn man im Menü mit dem Mauszeiger über die Chatleiste fährt, erklingt ein Ton. Aufgrund eines Fehlers wurde dieses Audio mehrmals pro Sekunde abgespielt, was natürlich allen auf die Nerven ging. Um das Problem zu beheben, mussten wir erst verstehen, wie Widgets mehrere Male pro Einzelbild Mausereignisse empfangen und wie das zugehörige Timing funktioniert.

    Methoden beim Testen

    Globale Invalidierung wirkt sich auf alle Aspekte des Spiels aus. Ohne Ausnahme. Buchstäblich.

    Deine Freundesliste? Globale Invalidierung. Die Schaltfläche, die dich in die Warteschlange wirft? Globale Invalidierung. Das Einstellungsmenü? Dreimal darfst du raten. Meine Kopfschussrate? Ähm …

    Es gibt überall im Spiel Elemente der Benutzeroberfläche und sie teilen Spielern wichtige Informationen mit. Diese Elemente durften unter keinen Umständen kaputtgehen.

    Also stellte unsere Qualitätssicherung einen Testplan mit mehreren Strategien zusammen, um mit Zuversicht sagen zu können, dass die globale Invalidierung auch wie gewünscht funktionierte.

    Tests im „Vertical Slice“

    Ein „Vertical Slice“ ist in der Spieleentwicklung eigentlich eine kurze Demo, die einen Eindruck vom Spiel vermitteln soll. In VALORANT stellt es die Hauptinteraktionen der Spieler dar, vom Start des Clients bis hin zur Warteschlange, dem kompletten Match und dem Spielergebnis-Bildschirm. So konnte sich die Qualitätssicherung auf die kritischen Elemente des Spiels konzentrieren, die am häufigsten verwendeten Elemente schnell testen und Probleme schon früh identifizieren.

    Zerstörerische Tests

    Nach dem „Vertical Slice“ ging das zerstörerische Testen an den Start. Diese Art von Tests dient der Ermittlung von Problemen, die von der Norm abweichen, häufig durch Änderung externer Faktoren (z. B. Netzwerk-Ping, Bildrate, Wechsel zwischen Programmen mit ALT und TAB usw.). Mithilfe einer Reihe interner Werkzeuge verbrachten die Qualitätssicherer mehrere Wochen mit zerstörerischen Tests.

    Grenzfall-Tests

    Viele Teile von VALORANT bekommt nur ein kleiner Prozentteil der Spielerschaft zu Gesicht. Einige Bereiche sieht man nur ein einziges Mal (z. B. die Einführung für neue Spieler). Auch wenn diese Elemente nicht so oft aufgerufen werden, sind sie trotzdem wichtig. Um auch versteckte Fehler zu finden, mussten wir also unsere Grenzfälle identifizieren und testen.

    Tests auf der PBE (Öffentliche Beta-Testumgebung)

    Die PBE war für die globale Invalidierung ein großer Meilenstein.

    • Zum ersten Mal konnten externe Spieler die Funktion ausprobieren. Das hieß auch, dass die globale Invalidierung unter den Bedingungen der „echten Welt“ getestet wurde.
    • Auf der PBE gibt es viele verschiedene Hardwarekonfigurationen. Die PBE deckt bewusst ein ganzes Spektrum an Rechnern ab, von Einsteiger bis High End, und dank der unterschiedlichen Endgeräte konnten wir sehen, wie die globale Invalidierung sich auf die Spielerschaft auswirken würde.

    Nach dem PBE-Test am Wochenende des 22.–23. Januar 2022 konnten wir mit Zuversicht sagen, dass die globale Invalidierung die kompetitive Integrität nicht negativ beeinflusste und die Leistungsverbesserungen unseren Erwartungen entsprachen.

    Globale Invalidierung für alle

    Als die globale Invalidierung mit Patch 4.03 live ging, behielten wir die Fehlermeldungen der Spieler genau im Auge. Außerdem überwachten wir die Leistungsdaten, um sicherzustellen, dass sich unsere Schätzungen mit den realen Ergebnissen deckten. Letzten Endes war die globale Invalidierung ein großer Erfolg für unsere Spieler, und wir hoffen, dass du von der verbesserten Bildrate profitierst.

    Da die globale Invalidierung jetzt im Live-Spiel ist, macht sich das Leistungsteam wieder daran, weiter zu optimieren. Bis zum nächsten Mal und viel Spaß beim Fraggen!