Next generation .Net
La GROSSE session .Net de la Build.
Je ne vais pas couvrir toute la session dans ce poste (les annonces concernant .Net Foundation et roslyn étant déjà bien relayées), mais me concentrer sur la partie la plus barbue : le nouveau compilateur JIT et SIMD pour C#, ainsi que .Net Native
2 modes de configuration
Dans la prochaine version de .Net, on aura 2 modes de compilation : une compilation Just-in-time, particulièrement adaptée aux scénarios où il y’a de la génération de code at runtime (nécessaire pour les frameworks d’injection de dépendance, les ORM, la génération automatique de proxy WCF, etc.), et la compilation native (ne supportant pas ces scénarios de génération de code dynamique).
RyuJIT le nouveau compilateur Just-in-time
Au tout début de .Net, le seul compilateur JIT produit par Microsoft était le compilateur x86. Comme il n’y avait qu’une seule architecture cible, le JIT n’a pas été pensé de manière très modulaire. Quand Microsoft a décidé de supporter X64, l’équipe .Net a donc du ré-écrire un JIT compiler from scratch pour cette architecture. De même à l’époque de Compact Framework (sous Windows CE), un nouveau JITter pour les processeurs ARM de l’époque a été nécessaire. Si l’on rajoute ca, le compilateur pour Silverlight sur PC, sur Mac, celui pour PowerPC de la XBox 360, celui pour les processeurs ARM pour WP7, pour WP8, celui optimisé pour Snapdragon 800, et le prochain gérant ARM64, on imagine bien que le fait d’avoir des implémentations complètement différentes d’une architecture à l’autre n’est pas tenable… Surtout si en plus de les maintenir on demande en plus d’améliorer l’efficacité du code généré d’une version à la suivante !
C’est à partir de ce constat que Microsoft s’est lancé sur la nouvelle génération de JIT Compiler connue sous le nom de RyuJIT. RyuJIT est une réécriture complète, très modulaire du compilateur JIT, avec un focus porté sur les performances (à la fois en terme de quantité de code MSIL par cycle CPU, qu’en terme d’efficacité du code généré), ainsi que sur la réutilisation d’un framework commun entre toutes les architectures ciblées. Même dans la version préliminaire disponible actuellement, RyuJIT est du coup déjà plus performant que le JIT classique.
De plus, comme les différentes déclinaisons de RyuJIT reposent sur un socle commun, il est plus facile pour l’équipe .Net d’apporter de nouvelles fonctionnalités de bas niveau à chaque plateforme, et pour prouver cela, la CTP3 de RyuJIT supporte désormais les instructions SIMD !
RyuJIT et SIMD
SIMD est l’acronyme de “Single instruction multiple data”. Les instructions SIMD permettent en effet d’appliquer la même opération sur plusieurs opérandes simultanément sur un même processeur. C’est quelque chose de très utilisé dans les applications mathématiques ou dans les jeux vidéos par exemple. En effet toutes les opérations arithmétiques sur des vecteurs peuvent être accélérées de cette manière : par exemple une addition de 2 vecteur à 3 dimensions consiste à applique la même opération d’addition aux 3 membres de chaque vecteur.
Au niveau du processeur, ca se présente sous la forme du support de jeu d’instructions spéciaux (SSE2, ARM Neon, Intel AVX…), et de la présence de registres spéciaux de grande capacité utilisés par ces instructions (128bit pour SSE et ARM Neon, 256bit pour AVX). RyuJIT expose des informations permettant d’exploiter ces instructions de manière très simple (sans avoir à connaitre les jeux d’instructions SSE, ARM Neon etc.), via la librairie nuget Microsoft.Bcl.Simd.
En terme de chiffres, on peut s’attendre à des gains de performance de quasiment x4 pour SSE2 et ARM Neon, et même de x8 pour AVX pour les algorithmes vectorisables. C’est assez énorme !
.Net Native
Pour les applications Store (Windows et Windows Phone), .Net va supporter la compilation directe en code natif. Pour se faire, Microsoft a créé un frontend de compilateur capable de comprendre le code MSIL et de le présenter au backend du compilateur C++ ! Du coup on bénéficie de la productivité de C#, et de la maturité et de l’efficacité du compilateur C++. Un exemple d’optimisation apportée par le compilateur C++, est l’auto-vectorisation et l’auto-parallélisation de code ! En effet, le compilateur C++ est capable de voir que lorsque vous parcourez un tableau pour effectuer des traitements mathématique, il peut regrouper ces opérations en utilisant des instructions SIMD ! Même plus besoin de Microsoft.Bcl.Simd ! Et de la même manière, si il voit qu’il peut le faire sans risque, le compilateur C++ est capable d’automatiquement paralléliser les boucles pour profiter de toute la puissance des processeurs multi-core ! En bref, des optimisations énormes qui ne sont pas possibles avec compilateur JIT (mais qui nécessitent par contre des temps de compilation sensiblement plus longs).
En bref, une session vraiment Deep dive, et extrêmement rassurante sur le futur de .Net : les investissements réalisés par Microsoft dans ces 2 briques sont très significatifs, et l’on imagine bien qu’ils vont vouloir capitaliser dessus !
Commentaires