Un meilleur jeu avec Burst 1.7

La dernière version du paquet Burst apporte de grandes améliorations au niveau du temps d'itération et de l'inspecteur Burst. Dans ce billet, nous allons voir ce qui a changé et comment notre technologie de compilateur C# haute performance (HPC#) peut désormais vous aider à améliorer les performances sur toutes les plateformes avec encore plus de facilité.
Alors que notre pile technologique DOTS s'appuie sur Burst pour fournir un code hautement optimisé, Burst est un paquet autonome, disponible dans le gestionnaire de paquets pour Unity 2019.4 ou plus récent. Des milliers de vos projets sur les principales plates-formes de bureau, de console et mobiles tirent déjà parti de Burst.
Dans les versions précédentes de Burst, nous avons fait des progrès considérables pour améliorer l'expérience quotidienne de travail avec Burst. Dans Burst 1.7, nous avons poursuivi cette tendance en nous concentrant sur l'amélioration du temps d'itération. Qu'entend-on par temps d'itération ? Nous entendons par là la "boucle interne" du développement : vous apportez une modification à un script C#, revenez à l'éditeur, attendez la fin de la compilation du script, attendez la fin de la compilation de Burst, puis passez en mode "Play" pour tester votre modification.
Dans Burst 1.7, nous avons considérablement réduit le temps d'attente pour Burst, pour le scénario courant qui consiste à apporter quelques modifications au code de votre jeu et à le tester en mode Play. La compilation en rafale intervient désormais plus tôt dans le pipeline (immédiatement après que le pipeline de compilation de scripts a terminé la compilation des assemblages .NET), de sorte que, dans de nombreux cas, elle est terminée au moment où le code résultant doit être exécuté. Au lieu de compiler chaque point d'entrée Burst séparément, comme c'était le cas dans les versions précédentes de Burst, les points d'entrée Burst (par exemple, un job ou un pointeur de fonction) sont désormais regroupés afin d'améliorer le rendement du compilateur et de réduire le nombre de bibliothèques que l'éditeur doit charger.
Burst 1.7 comprend également une amélioration majeure des performances de l'appel direct. L'appel direct est une fonctionnalité que nous avons ajoutée à Burst 1.5 et qui permet au code C# géré d'appeler directement une méthode compilée par Burst, sans passer par BurstCompiler.CompileFunctionPointer. Lors d'un rechargement de domaine, un travail d'initialisation doit être effectué pour câbler les méthodes d'appel direct, et dans Burst 1.7, nous avons rendu cette initialisation jusqu'à 33 fois plus rapide.
Pour terminer sur le sujet du temps d'itération, nous avons examiné le coût de l'initialisation de SharedStatic. SharedStatic est un mécanisme qui permet le partage de données entre managed C# et HPC#. Dans Burst 1.7, nous avons rendu l'initialisation de SharedStatic jusqu'à 13 fois plus rapide.
Les graphiques suivants montrent l'amélioration des performances de Burst 1.7 par rapport à Burst 1.6. Les mesures ont été prises dans le cadre d'un grand projet client. Le premier graphique ci-dessous montre des temps pris avec un chronomètre (un vrai chronomètre, pas System.Diagnostics.Stopwatch) en observant l'éditeur, de sorte qu'ils devraient refléter le type d'améliorations que vous pouvez vous attendre à voir dans l'utilisation quotidienne.

Le deuxième graphique ci-dessous se concentre uniquement sur l'éclatement, et exclut donc tout ce qui peut se produire dans l'éditeur. Pour ce projet particulier et ce fichier modifié, Burst 1.7 est plus rapide que Burst 1.6 dans les trois délais :
- Cache froid - Burst n'a pas encore mis en cache les résultats de la compilation du code de votre projet.
- Cache chaud - Burst a déjà compilé le code de votre projet et doit charger les résultats de la compilation en cache à partir du disque.
- Modification d'un fichier - Après la modification d'un fichier, Burst vérifie quels points d'entrée doivent être recompilés et les compile. Notez que l'amélioration apportée par Burst 1.7 dépend généralement du fichier modifié . Par exemple, si vous modifiez une méthode utilisée par tous les points d'entrée de Burst, la différence entre Burst 1.6 et Burst 1.7 sera plus faible. Dans cet exemple, c'est la méthode du point d'entrée elle-même qui a été modifiée.

Burst Inspector (accessible via Jobs > Burst > Open Inspector...) est un outil incroyablement utile pour le travail d'optimisation. Cet outil vous permet de visualiser le code assembleur qui sera exécuté sur le(s) processeur(s) cible(s). Dans Burst 1.7, nous avons ajouté plusieurs fonctionnalités très demandées. Une capture d'écran en dit long, alors sans plus attendre :

Comme vous pouvez le constater, nous avons ajouté des marqueurs de branche pour faciliter la visualisation des chemins d'exécution du code. Notez que les marqueurs de branche peuvent être désactivés à l'aide de la case à cocher "Afficher le flux de branche" afin qu'ils ne vous gênent pas lorsque vous n'en avez pas besoin. Un aspect particulièrement intéressant de cette fonctionnalité est que vous pouvez cliquer sur une flèche de flux de branches et vous rendre à l'autre extrémité de la flèche, comme ceci :
Exemple de clic sur un marqueur de branche pour passer à la destination de la branche
Les blocs de désassemblage moins importants (par exemple, les directives ou les données constantes) sont désormais automatiquement réduits, mais il est toujours possible de les faire basculer lorsque l'on souhaite les visualiser.
Une autre nouveauté de Burst 1.7 est la possibilité de sélectionner une partie du désassemblage et de la copier.
Exemple de sélection et de copie d'une section spécifique du désassemblage
Voici une liste d'améliorations plus modestes mais non moins importantes apportées par Burst 1.7.
- Les API Arm Neon vst1* sont désormais entièrement prises en charge. Nous avons ajouté ces API dans Burst 1.6, mais nous les avons gardées derrière une #define expérimentale. Dans Burst 1.7, ils ne sont plus protégés par cette #define et sont entièrement pris en charge.
- System.Span<T> et System.ReadOnlySpan<T> sont désormais pris en charge dans le code Bursted. Ces types ne sont pas autorisés en tant qu'arguments de point d'entrée.
- Burst utilise désormais la version 12.0.0 de LLVM par défaut, ce qui lui permet de bénéficier des dernières améliorations apportées par le projet LLVM en matière d'optimisation.
- Nous avons modifié le pipeline d'optimisation de LLVM pour exécuter le dérouleur de boucle exclusivement après le vecteur de boucle. Cela permet d'améliorer le codegen dans de nombreux cas.
- Nous avons fait en sorte que fmod et le module en virgule flottante utilisent un algorithme plus rapide pour améliorer les performances.
- Burst génère maintenant un link.xml automatiquement pour éviter le dépouillement de l'IL, causant des symboles manquants à l'exécution à cause de l'utilisation d'un constructeur statique.
- Nous avons amélioré les performances du compilateur lors des copies de grandes structures en détectant davantage de cas où un chargement/stockage peut être converti en toute sécurité en une opération de déplacement de mémoire.
- Nous avons modifié la façon dont nous affichons les temps lorsque l'option "Show Timings" est activée dans le menu Burst. En nettoyant et en présentant les informations de manière plus claire.
Notez que Burst 1.7 est la dernière version à prendre en charge Unity 2019.4. La prochaine version de Burst nécessitera au minimum Unity 2020.3. Si vous avez des idées, des questions ou si vous souhaitez simplement nous faire part de ce que vous faites avec Burst, n'hésitez pas à nous laisser un message sur le forum Burst.
