.NET 5 : Benchmark.NET est dorénavant l'outil canonique pour mesurer la performance du code .NET
voici un aperçu des améliorations de performances à venir dans .NET 5

Stephen Toub, ingénieur logiciel chez Microsoft et aussi membre de l'équipe .NET, a publié un long billet, peut-être le plus long jamais publié sur .Net, dans lequel il a documenté toutes les améliorations de performances à venir dans .NET 5, une étape importante dans l’unification de .NET qui débutera en novembre. Dans ce billet, Toub met en avant plus de 250 demandes d'extraction faites via GitHub dans le cadre de l'effort commun pour la création de .NET 5, annoncé au cours de la conférence des développeurs Build 2019. Voici un aperçu de ce qu’il a présenté.

Configuration

Benchmark.NET est dorénavant l'outil canonique pour mesurer la performance du code .NET, ce qui permet d'analyser facilement le débit et l'attribution des extraits de code.

GC

Selon Toub, le ramasse-miettes dans .Net est souvent en tête des préoccupations. Ainsi, à partir de .Net 5, plusieurs efforts sont consacrés à la réduction de l'allocation, non pas parce que l'acte d'allocation est en soi trop coûteux, mais en fonction des coûts de nettoyage consécutifs à ces allocations par l'intermédiaire du ramasse-miettes GC. Cependant, peu importe la quantité de travail nécessaire pour réduire les allocations, la grande majorité des charges de travail les supportera, et il est donc important de repousser continuellement les limites de ce que l'éboueur est capable d'accomplir, et à quelle vitesse.


JIT

Toub a précisé que NET 5 est aussi une version passionnante pour le compilateur Just-In-Time (JIT), apportant de nombreuses améliorations de toutes sortes qui se retrouvent dans la version. Comme c’est le cas pour tous les compilateurs, les améliorations apportées au JIT peuvent avoir des effets de grande portée. Parfois, certaines modifications individuelles ont un impact limité sur un morceau de code individuel, mais elles sont ensuite amplifiées par le nombre d'endroits où elles s'appliquent.

Intrinsics

Selon le billet, dans .NET Core 3.0, plus d'un millier de nouvelles méthodes Intrinsics au matériel ont été ajoutées et reconnues par JIT pour permettre au code C# de cibler directement des jeux d'instructions comme SSE4 et AVX2. Elles ont ensuite été utilisées à bon escient dans un ensemble d'API dans les bibliothèques centrales. Toutefois, les éléments Intrinsics étaient limités aux architectures x86/x64. Dans .NET 5, beaucoup d'efforts ont été consacrés à l'ajout de milliers d'autres, spécifiques à l'ARM64, grâce à de multiples contributeurs. Et comme pour leurs homologues x86/x64, ces nouvelles méthodes ont été mises à profit dans les fonctionnalités de la bibliothèque centrale.

Runtime Helpers

Toub a expliqué que le ramasse-miettes GC et le compilateur JIT représentent une grande partie du temps d'exécution, mais il reste encore des portions significatives de fonctionnalités dans le temps d'exécution en dehors de ces composants. Dans .Net 5, ceux-ci ont également connu des améliorations. Il est intéressant de noter que JIT ne génère pas de code à partir de zéro pour tout. Il existe de nombreux endroits où des fonctions d'aide préexistantes sont sollicitées par JIT, et c’est le runtime qui fournit ces aides. Ainsi, les améliorations apportées à ces fonctions d’aide peuvent avoir un impact significatif sur les programmes.

Toub a aussi précisé que dans les bibliothèques comme System.Linq, l’équipe a évité d'ajouter des vérifications de type supplémentaires pour les interfaces covariantes en raison de leur surcharge nettement plus importante que pour les interfaces normales.

Traitement de texte

En effet, le traitement de texte est le pain quotidien de nombreuses applications, et beaucoup d'efforts sont déployés à chaque version pour améliorer les éléments fondamentaux sur lesquels repose tout le reste. Ces changements vont de la micro-optimisation des aides au traitement de caractères individuels à la refonte (révision) de bibliothèques entières de traitement de texte. System.Char a reçu des améliorations dans .NET 5. À titre d’exemple, dotnet/coreclr a amélioré les performances de char.IsWhiteSpace en ajustant son implémentation pour qu'elle nécessite à présent moins d'instructions et moins de ramifications. Les améliorations apportées à char.IsWhiteSpace se manifestent ensuite dans un tas d'autres méthodes qui s'appuient sur elle, comme string.IsEmptyOrWhiteSpace et Trim.

Expressions régulières

Une technique d'analyse très spécifique, mais extrêmement courante consiste à utiliser des expressions régulières. L’équipe .Net 5 a publié durant le mois d'avril plusieurs améliorations de performances apportées au System.Text.RegularExpressions. L’une d’elles concerne la gestion des nouvelles lignes lors de la spécification de RegexOptions.Multiline, qui modifie la signification des ancres ^ et $ pour qu'elles correspondent au début et à la fin de n'importe quelle ligne plutôt qu'au début et à la fin de toute la chaîne d'entrée. Pour plusieurs expressions essayées par l’équipe, ces changements se traduisent régulièrement par des améliorations de débit de 3 à 6 fois, et dans certains cas, bien plus.

Threading and Async

L'un des plus grands changements concernant l'asynchronie dans .NET 5 n'est pas activé par défaut, mais constitue une autre expérience pour obtenir un retour d'information. Pour l'essentiel, dotnet/coreclr a introduit la possibilité pour async ValueTask et async ValueTask<T> de mettre implicitement en cache et de réutiliser l'objet créé pour illustrer une opération se terminant de manière asynchrone. Cela a pour avantage d’amortie la surcharge de ces méthodes, sans allocation. L'optimisation est actuellement opt-in, vous donc devez définir la variable d'environnement DOTNET_SYSTEM_THREADING_POOLASYNCVALUETASKS à 1 afin de pouvoir l'activer.

L'une des difficultés que pose cette activation concerne le code qui pourrait faire quelque chose de plus complexe que d'attendre simplement une certaine ValueTaskReturningMethod(), car les ValueTasks ont plus de contraintes que les Tasks quant à la manière dont elles peuvent être utilisées. Pour aider à cela, un nouvel analyseur UseValueTasksCorrectly a été publié qui signalera la plupart de ces utilisations abusives.

LINQ

Les précédentes versions du noyau de .NET ont connu un grand nombre de changements dans la base de code System.Linq, en particulier pour améliorer les performances. De nouvelles améliorations continuent d'être apportées à .NET 5, notamment des améliorations de performance dans LINQ. Une amélioration notable est dans OrderBy. En effet, il y avait de multiples raisons pour faire évoluer l'implémentation native de tri de Coreclr vers un code géré, l'une d'entre elles étant de pouvoir le réutiliser facilement dans le cadre de méthodes de tri basées sur la portée.

De telles API ont été exposées publiquement, et avec dotnet/runtime, l’équipe a pu utiliser ce tri basé sur la portée dans System.Linq. Cela a été bénéfique en particulier parce que cela a permis d'utiliser les routines de tri basées sur Comparison<T>, qui à leur tour ont permis d'éviter de multiples niveaux d'indirection sur chaque opération de comparaison.

Source : Microsoft

Et vous ?

Que pensez-vous des nouveautés annoncées pour NET 5.0 ?


Voir aussi

.NET 5.0 Preview 5 est disponible, avec un "petit" ensemble de nouvelles fonctionnalités et d'améliorations des performances, dont des changements apportés au compilateur RyuJIT JIT et autres

Avec .NET 5, Microsoft voudrait produire un environnement d'exécution .NET unique et une infrastructure utilisable partout

.NET 5 Preview 1 est disponible et apporte des améliorations des performances d'expression régulière, ainsi que des améliorations de la qualité du code dans RyuJIT