Stellaris, carnet des développeurs n°181 et 182 : Des Threads et des Checks.

Bonjour à tous, ici The French Paradox!

De la part de toute l’équipe de Stellaris, nous espérons que vous avez passé d’agréables vacances d’été malgré la situation actuelle !
Nous sommes de retour au travail (mais pas encore au bureau cependant). Les six prochains mois s’annonce déjà excitant avec tout un tas de nouveautés à venir. Nous sommes tout aussi excités de pouvoir les partager avec vous dans les semaines à venir!

Aujourd’hui j’ouvre la voie des nouveautés de la 2.8 avec un sujet des plus techniques que nous, les programmeurs, avons développé cet été. Le reste vous sera révélé par l’équipe au fur et à mesure des carnets futurs.
Sans plus de blabla, parlons des threads!

Threads? Quels threads? :

Il existe un gag récurrent qui dit que les fans se demandent toujours ce qui viendra en premier : Victoria III ou que les jeux paradox utilisent le multi-threading.


Sans mentir, je sais que certains d’entres vous pensent que nos réunions à haut niveau se passent ainsi.


J’ai bien peur qu’il me faut encore une fois réfuter le mythe, tous les jeux paradox utilisent le multi-threading que ça soit EU4 ou CK3, y compris Stellaris. Pour mieux expliquer ce meme et son origine je vais vous faire un peu d’histoire. On m’a dit que vous aimez ça l’histoire.

Pendant longtemps, l’industrie du logiciel s’est appuyé sur la “loi de Moore”, qui dit qu’un processeur est deux fois plus efficace/puissant/moins chère tous les deux ans. Ceci est resté vrai dans les années 90 alors que la fréquence des processeurs est passée de 50 Mhz à 1 Ghz en l’espace d’une décennie. Cette tendance a continué jusqu’en 2005 lorsque la barre des 3,8 GhZ fut atteinte. Puis la croissance de la vitesse d’horloge s’est arrêtée (NdT : En 2020 on commence à dépasser des 5GHz).

Il s’est avéré que passé cette fréquence les lois de la physique rendaient peu intéressantes des accélérations supplémentaires au delà des 3 ou 4 GHz. À la place les concepteurs de puces ont changé de direction et ont préféré augmenter le nombre de cœurs plutôt que d’accélérer un cœur unique. De plus l’importante vitesse atteinte à permis de doubler l’import d’informations au cœur afin de faire les calculs plus vite (NdT : imaginez manger votre bol de céréale avec deux cuillères plutôt qu’une afin de réduire les temps mort entre chaque déglutition, c'est le principe de l'hyperthreading chez intel ou SMT chez AMD). C’est pour cela qu’aujourd’hui je trouve qu’il est plus important de regarder le nombre de cœurs d’un processeur plutôt que sa fréquence. La loi de Moore reste valide mais la stratégie pour conserver cette situation a radicalement changée.
Ce changement de stratégie a profondément marqué l’industrie logicielle car si écrire un code sur un processeur allant plus vite est très facile, utiliser plusieurs cœurs n’est pas aussi trivial. Les programmes ne séparent pas leurs tâches en 2, 4 ou 8 morceaux tout seul et c’est notre travail à nous les programmeurs.

Le multi-thread pas forcément plus rapide :

Revenons alors à nos jeux et à cette questions récurrentes : les jeux PdX utilisent-ils le multi-threading? La réponse est bien sûr. On les utilise tellement que nous avons rencontré des problèmes avec des machines de 2 cœurs ou moins. Mais la bonne question serait : vos jeux utilisent-ils efficacement le multi-threading?. La réponse devient alors : ça dépend. Comme mentionné précédemment, une utilisation efficace de plusieurs threads est plus compliquée que d’optimiser le code pour fonctionner sur un cœur fonctionnant “plus vite”. Dans notre cas deux soucis se présentent : la séquence et l'ordonnancement. En gros lorsque de nombreuses actions se passent “simultanément” (comme lors d’un combat ou pour la génération des ressources), la résolution de certaines de ces actions ont des conséquences sur la résolution des actions suivantes. Si 2 populations produisent une ressource (3 d’énergie pour l’une et 4 pour l’autre) il peut arriver trois choses : l’addition se passe bien (donc 7 énergie) ou une seule valeur est prise en compte car la 1ere se fait écraser par la deuxième (et inversement) en raison de la valeur initiale mise en cache qui ne serait pas remise à jour à temps avant la prise en compte de la seconde valeur. Le second soucis est l’ordonnancement. Dans certains cas, il se peut que l’ordre des actions ait une importance capitale comme lors d’une bataille. En effet selon qui “tire” le premier, les résultats peuvent être radicalement différents. Qui plus est cet ordre est dépendant du matériel du joueur.


Blorg shoots first.

Lorsque cela arrive la réalité diverge entre les joueurs et conduit à une désynchronisation.
Il y a bien sûr plusieurs façon de résoudre ces problèmes comme une phase de consolidation des valeurs à la fin de l’opération (plutôt que des les appliquer en séries) afin d’éliminer l’ordre déterministe des choses.
Comme vous pouvez vous l’imaginez il est plus facile de commencer par penser aux threads avant de commencer le code et revenir à ce système une fois le code en place est difficile.

La bonne nouvelle :

Toutes ces explications sont intéressantes mais que contiendra le prochain patch? Vous serez heureux d’entendre que j’ai pu passer un peu de temps à refondre une partie du moteur du jeu : les fichiers et le système de chargement des assets.
Depuis longtemps nous utilisions un logiciel tier pour réaliser le travail. En conjonction avec le multi-threading et quelques autres optimisations nous avons drastiquement réduit le temps de chargement au lancement du jeu :


Cette comparaison est faite sur mon PC à la maison utilisant un i7 2600K et un SSD. Les deux démarrage était fait après le démarrage du PC mais dans mes tests même après plusieurs lancement le nouveau démarrage se fait beaucoup plus vite.
Pour voir cette accélération il vous faudra utiliser la bêta de DirectX11 utilisé tout d’abord par nos collègues de Tantalus qui s’occupent de la version console de Stellaris. Il sera intégré dans une version bêta du prochain patch. Ce changement permet une meilleure utilisation du multi-threading qui serait difficile de réaliser avec la version DirectX9. Joué avec l’ancien DX améliorera tout de même les performances au lancement mais vous ne verrez pas la barre bondir comme lorsque vous utilisez la version DX11.
Ces optimisations se retrouveront aussi aux nouvelles versions du moteur Clausewitz et font partie intégrante du lanceur de CK3. Imperator en bénéficiera aussi. Il sera possible de l’appliquer à HOI4 cependant pour EU4 en raison de la quantité de texte à charger l’amélioration des performances au lancement du jeu n’a pas été aussi probante.
Si vous voulez plus de détails sur les optimisations sur Stellaris je vous invite à aller voir mon un article sur mon blog (NdT : voir sur la source)

Je vous laisse maintenant. Ce sera surement mon dernier carnet sur ce jeu puisque je suis transféré à l’équipe d'HOI 4 le mois prochain pour diriger l’équipe de programmation. Ce fut un temps court sur Stellaris mais ne vous en faite pas même si je part, Jeff reste encore avec vous!



Bonjour à tous, je suis Caligula l’un des designer de contenu pour Stellaris ce qui se traduit par une grande variété de tâches incluant l’écriture narrative pour les événements et leurs scripts. Le script étant notre terme pour quelque chose ressemblant à de la programmation mais sans toucher au code source. En d’autres mots je réalise la même chose qu’un modeur (en ayant l’avantage de demander à changer le code source si besoin). Tous les designers ont leur domaine et le mien sont les scripts des systèmes complexes (ou qui posent problèmes, la guerre des cieux me donne encore des cauchemars).
Nous avons plein d'excitantes nouveautés à vous montrer dans les semaines et les mois à venir mais pour aujourd’hui inspiré par plusieurs questions de la semaine dernière je vais continuer de vous parlez du sujet des scripts pour des modeurs amateurs et particulièrement sur ce qui pourrait causer de mauvaises performances en jeu.

L’outil de scripts de Stellaris est très puissant et beaucoup peut être réaliser avec. Mais attention, ce n’est pas parce que quelque chose est possible qu’il faut le faire. Il faut le souligner (et je parle d’expérience ici) cette attitude va très certainement impacter les performances en jeu et aussi un code imbitable que vous ne serez pas en mesure de corriger/comprendre même après six mois de travaux lorsque vous réalisez qu’il ne fonctionne pas en partie. Cependant il faut voir que faire les choses par du code (NdT : code source) est par définition plus rapide. Avec du code, il est possible de vérifier si une fonction marche correctement avec un seul check alors que si c’est du script, il faut d’abord traduire votre écrit en code avant de pouvoir faire votre vérification. D’où le faite qu’une partie des commandes soit hard codée pour aller plus vite et que certaines acrobaties du script pour résoudre des problèmes au sein du jeu le rende encore pire. D’où la première question à propos de la nécessité de votre solution.

Mais pourquoi je m’embête à dire cela, je parle à des modeurs qui vont de toute façon faire ce qu’ils veulent donc sans plus attendre ...

Qu’est ce qui cause les problèmes de performance :

À chaque fois que vous faite un check ou que vous exécutez un effet, cela prend une partie de votre puissance de processeur. Avec quelques exceptions qui seront très rares (j’en reparlerai), tout ceci est totalement normal et même nécessaire pour jouer. C’est lorsque les checks sont répétés trop souvent, sur de trop nombreux objets que les problèmes surviennent. Dans Stellaris les populations sont le plus souvent en cause quand bien même faire un check sur toutes les populations de la galaxie est une très mauvaise idée.

La première étape pour améliorer le script est de revoir son déclenchement. La meilleur façon de faire est de forcer son fonctionnement via des prérequis définis plutôt que d’attendre le temps moyen d’apparition (MTTH) ou encore pire de faire en sorte que l’événement arrive tous les jours. Si un degré d’aléatoire est nécessaire un événement caché peut aussi être utilisé avec un délais aléatoire entre deux tirage (comme pour l’événement action.220).

Bien sûr tout n’est pas qu’événement et malheureusement dans Stellaris, beaucoup de changements interviennent par les populations. La répartition des activités et autres déclencheurs dans le fichier des activités par exemple ont été pointé du doigt dans le passé (NdT : tous les jours, toutes les populations de toutes les planètes subissaient un check pour savoir si elles étaient mieux qualifiées pour remplir l’activité nécessitant une population). Le premier principe est maintenant qu’il est déconseillé de jouer avec les scripts autour des activités.

Que peut-on faire ?

Éviter les boucles, être sûr que ses événements sont déclenché de la bonne façon et en évitant le plus possible les checks sur les populations si possible. Mais il est possible de faire plus (NdT : cette partie est très résumé et si vous êtes curieux la source est disponible en fin d’article).
- Toujours Utiliser le bon périmètre : si vous cherchez à faire un check sur les différents empires il vous est possible de réduire la recherche en sélectionnant des conditions supplémentaires afin d’éviter de check les amibes ou un léviathan si il ne vous faut que vos partenaires au sein d’une fédération. Il est parfois inévitable d’utiliser un périmètre de check très large mais vous pouvez aussi trouver des conditions qui vous évitent alors de faire ce check. Je recherche toutes les planètes avec deux mineurs, je peux soit prendre toutes les planètes avec plus de deux habitants puis compter les mineurs où d'abord choisir les planètes avec des mineurs avant de les compter.
- Les conditions peuvent parfois requérir beaucoup de puissance : tous les checks ne sont pas égaux, le faire sur une valeur particulière est très simple. Cependant si le jeu doit recalculer cette dernière avant d’en faire le check, cela prendra beaucoup plus de temps. Créer de nouvelles conditions en jeu prend aussi beaucoup de temps parce que c’est à la fois compliqué (le “create_species effect” est composée de plus de 600 lignes de code) et qu’en plus il faut recalculer des valeurs qui viennent de partout. Mais parfois il faut le faire et il est recommandé d'utiliser des coupes circuits pour déclencher l'événement dès que les conditions sont réunies plutôt que de tout tester puis de renvoyer un résultat.

La Bonne Année :

Je ne pouvais pas passer à côté du gel du nouvel an. Nous jouions en multijoueur et étions très avancé dans la partie. Étant tous chez nous et avec une connexion internet pas des plus rapide, le jeu avançait assez lentement. Soudainement, nous notions d’énorme ralentissement à chaque début d’année. Tellement énorme qu’on a commencé à faire une blague de nouvel an à chaque fois que le jeu n’avançait plus!
Le bug provenait de l’assimilation en synthétique de populations de larges empires. En effet l’assimilation est devenu un script et pour être franc n’aurait pas dû être faite comme elle l’est et fonctionne en déclenchant un événement chaque premier janvier. Ce dernier se déclenche sur toutes les planètes avec un habitant en cours d’assimilation et choisissait aléatoirement lesquelles allaient passer synthétique en réalisant jusqu’à 4 fois la même boucle. Les performances en étaient fortement impactées (NdT : plus de détails en sources).
Après plusieurs essais, nous avons changé la façon dont il fonctionne et un gain de 50% a pu être constaté.

C’est tout pour moi! Je suis conscient que ce carnet était difficile à suivre pour une partie d’entre vous mais j’espère que vous l’avez trouvé intéressant . Pour conclure je dirais que les plus intrépide d’entre vous peuvent me contacter s’ils ont plus de questions à ce propos. Ne vous en faite pas, je pense qu’il n’y a rien de plus satisfaisant que de rendre quelques chose d’horrible plus élégant.


La reprise des carnets de Stellaris sous le signe des performances et du code, mais les nouveautés ne tarderont pas. Comme à l'habitude, vous pouvez réagir sur le forum dédié.