Les Blueprints sont-ils plus lents que le C++ ?
Lors de l'Unreal Fest 2024, Ari Arnbjornsson ingénieur senior chez Epic Games a donné une conférence sur le mythe des meilleures pratiques dans Unreal Engine.
Il y en a un qui revient particulièrement souvent : Blueprints ou C++ ? Qui est le plus rapide et quand doit on utiliser le C++ ? Vous avez probablement déjà entendu parler des blueprints et de leurs consommation face au C++. Mettons-les à l'épreuve et découvrons ce qu'il en est vraiment.
Les Blueprints sont-ils plus lents que le C++ ?
Les Blueprints sont le langage de script visuel d'Unreal Engine.
Parlons des Blueprints
Les Blueprints s'exécutent dans une machine virtuelle, et en tant que tel, il y a un surcoût pour chaque appel de Blueprint. Mais après cette surcharge, un node fonctionnera purement en C++. Ainsi, si vous n'avez que quelques appels BP, vous n'aurez qu'un surcoût négligeable.
La consommation du Blueprint
Lorsque vous appelez un node BP déclaré en C++, vous rencontrez un surcoût qui, sur ma machine, est d'environ 0,8 microseconde (μs) dans l'éditeur, et d'environ 0,7 μs dans un jeu packagé.
Il y a également un surcoût entre chaque node. Sur mon ordinateur, ce délai est d'environ 0,5 microseconde (μs) dans l'éditeur, mais de 0,1 μs dans un jeu packagé.
Mais encore une fois, comme pour le mythe du Tick, cela prend tout son sens lorsque nous le replaçons dans son contexte.
Par exemple, à quoi ressemble cet consommation de blueprint si la fonction DoWork effectue un travail d'une durée de 1 ms ?
La surcharge BP entre les nodes apparaît sous la forme d'un espacement entre les lignes PrintString et DoWork, qui n'est pas vraiment visible dans cette capture Insights.
Et la surcharge de BP pour l'appel à une fonction C++ apparaîtra comme un décalage entre les blocs DoWork et DoWorkC++. Encore une fois, ce n'est pas visible ici.
Si vous appelez un seul node qui effectue beaucoup de travail en C++, la surcharge BP est à peine perceptible. Cette fonction ne sera pas 10 fois plus lente simplement parce qu'elle est en BP. Dans ce cas, elle est plutôt 0,0001% plus lente.
Mais c'est rare, vous n'appellerez pas souvent des fonctions C++ qui prennent 1ms+, c'est comme quatre mises à jour de CharacterMovementComponent. Les temps des fonctions C++ les plus réalistes se situent plutôt entre 10 et 100 μs. Voyons cela.
Ici, DoWork prend 100 μs, soit 0,1 ms. C'est un temps plus courant pour les fonctions C++, ce qui est particulièrement évident ici puisque nous pouvons voir que les fonctions PrintString prennent également environ 90 μs.
Si vous plissez les yeux très fort, vous pouvez voir que nous avons maintenant un pixel de surcharge BP entre le premier PrintString et DoWork, et à peu près le même décalage entre DoWork et DoWorkC++. Dans ce cas, la surcharge BP est encore négligeable. Mais que diriez-vous de diviser à nouveau le travail par dix ?
Pour les fonctions C++ plus rapides, autour de 10 μs, nous commençons à voir la consommation. Ici, il y a un écart entre les nodes, et le décalage de 0,8 μs entre DoWork et DoWorkC++ apparaît clairement. Mais qu'en est-il si la fonction C++ est dix fois plus rapide ? Une fonction super rapide ?
Le total de consommation du BP est maintenant plus important que le travail effectué par le code C++. Il s'agit cependant d'une fonction C++ très rapide.
À quel point les Blueprints sont-ils plus lents ?
Pourquoi est-ce que je vous montre tous ces graphiques de temps d'exécution C++ ? C'est pour bien faire comprendre que la consommation de Blueprints n'est pas vraiment un multiplicateur, comme « les BP sont 10x plus lents que le C++ ». Il s'agit plutôt d'un surcoût par node. Bien sûr, certains graphes BP peuvent être environ 10x plus lents, mais cela dépend vraiment des nodes BP auxquels le graphe fait appel et de la lenteur des fonctions C++ qu'ils appellent. Si vous faites principalement des nodes mathématiques, que vous définissez des variables et que vous faites des boucles dans des tableaux, alors la plupart de ce temps sera consacré à de la consommation Blueprint.
Comprendre cela vous aidera à mieux savoir quand utiliser les BP et quand convertir en C++.
Meilleures pratiques en matière de Blueprints
Ci-dessousi l'avis de Michael Allar sur ce point, car c'est lui qui l'a le mieux exprimé :
D'accord, c'était assez court, laissez-moi en ajouter un peu plus :
Si la consommation de BP pour un certain code vous cause des problèmes, déplacez ce code en C++. Il n'y a pas de trophée pour la livraison d'un jeu en BP uniquement. Il y a cependant un prix pour le meilleur jeu. Vous pourriez finir par n'écrire que deux fonctions C++ pour faire fonctionner votre jeu, et c'est tout à fait normal.
Cela ne vous mènera qu'à un certain point. Souvent, vous en faites tout simplement trop, qu'il s'agisse de BP ou non. Vous ne pouvez convertir une fonction en C++ qu'une seule fois, si elle est toujours lente, vous devrez trouver un autre moyen de l'optimiser. Et cette optimisation aurait été valable que vous soyez en BP ou en C++.
Comment savoir quelles fonctions sont tellement surchargées en BP qu'elles devraient être transférées en C++ ? Utilisez les outils de profilage !
« Les Blueprints sont plus lents que le C++ », vrai ou faux ?
Ce n'était pas une question piège. A cause de la surcharge BP, les blueprints sont définitivement plus lents que le C++. C'est donc VRAI.
Cependant, cela ne signifie pas que vous ne devriez pas les utiliser, ils sont très polyvalents et rapides à mettre en œuvre et ils permettent aux non-codeurs de l'équipe de contribuer au code.
On me demande souvent quel est le meilleur ratio entre BP et C++, et après de nombreuses recherches et mesures, je suis heureux d'annoncer que j'ai finalement trouvé la seule vraie réponse à cette question : c'est le ratio entre les deux qui permet d'équilibrer votre jeu.
La plupart des jeux AAA utilisent beaucoup de Blueprints. Dans Fortnite, nous utilisons, et je cite l'un de nos ingénieurs, « BEAUCOUP » de Blueprints.