1 points par GN⁺ 2025-05-11 | 1 commentaires | Partager sur WhatsApp
  • La dernière version Sep 0.10.0 atteint une vitesse remarquable de parsing CSV de 21 Go/s sur un AMD 9950X
  • Les performances progressent fortement grâce à la prise en charge d’AVX-512 et au contournement des problèmes liés aux registres de masque
  • Un nouveau parseur AVX-512-to-256 surpasse les parseurs AVX2 et AVX-512 existants
  • En environnement multithread, 1 million de lignes sont traitées en 72 ms avec une bande passante de 8 Go/s
  • Grâce à une optimisation continue du logiciel et du matériel, les performances ont été multipliées par environ 3 en deux ans

Sortie de Sep 0.10.0 et vue d’ensemble des gains de performance

  • Dans sa récente version 0.10.0, Sep a optimisé la prise en charge des CPU compatibles AVX-512 (par ex. AMD 9950X, Zen 5) et mis à jour ses benchmarks
  • La dernière version affiche un résultat impressionnant de 21 Go/s pour le parsing CSV de bas niveau
  • Par rapport à la version précédente, cela représente une hausse marquée depuis 18 Go/s
  • Les détails des améliorations sont disponibles dans les releases GitHub et le README de Sep
  • L’article explique comment du code C# basé sur SIMD et de l’assembleur SIMD x64 ont permis d’améliorer les performances en contournant l’inefficacité du code machine AVX-512 de .NET 9.0

Évolution des performances de Sep

  • L’évolution de Sep, de la version 0.1.0 à 0.10.0, de .NET 7.0 à 9.0, et de l’AMD 5950X (Zen 3) au 9950X (Zen 5), est présentée visuellement
  • Les benchmarks sont réalisés en mono-thread et peuvent varier légèrement selon les releases
  • Le message clé est que les grands refactorings (comme la réécriture de la structure interne en 0.2.0) et l’accumulation de petites optimisations ont continuellement amélioré les performances
  • Grâce aux progrès conjoints du matériel et du logiciel, la vitesse de parsing a été multipliée par environ 3 en deux ans pour atteindre 21 Go/s
  • Le seul changement de génération matérielle (5950X→9950X, 4,9→5,7 GHz) justifie déjà un gain supérieur à 1,2x

Génération de code AVX-512 et problème des registres de masque

  • Sep prend en charge AVX-512 depuis la version 0.2.3, mais son usage des registres de masque AVX-512 (k1-k8) restait limité
  • Sous .NET 8, l’absence de prise en charge directe des registres de masque entraînait des copies et conversions répétées entre registres normaux, ce qui dégradait les performances
  • Au début, faute de CPU dédié compatible AVX-512, des tests limités sur un Xeon Silver 4316 avaient confirmé qu’il s’agissait malgré tout de l’option la plus rapide

Upgrade vers le 9950X et comparaison AVX-512 vs AVX2

  • Après un récent upgrade CPU de Zen 3 (5950X) vers Zen 5 (9950X), les benchmarks de Sep ont atteint 18 Go/s
  • En comparant directement les parseurs AVX-512 et AVX2, résultat quelque peu surprenant, AVX2 s’est montré environ 10 % plus rapide, à près de 20 Go/s
  • Cela suggère que l’inefficacité du traitement des registres de masque par le JIT .NET reste un problème

Code du parseur, analyse assembleur et nouveau parseur AVX-512-to-256

  • Tous les parseurs de Sep traitent des spans de caractères de 16K et utilisent des comparaisons basées sur des registres SIMD (Vector256, etc.)
  • SIMD permet d’identifier rapidement les caractères spéciaux (retours à la ligne, guillemets, délimiteurs, etc.) puis de les convertir en bitmasks afin d’optimiser les opérations ensemblistes
  • Le parseur basé sur AVX-512 souffrait de nombreuses opérations superflues à cause des transferts répétés entre registres de masque (k1, etc.) et registres généraux (zmm, etc.)
  • Dans la version 0.10.0, l’appel à MoveMask est avancé afin de réduire au minimum les conversions de masque inutiles, ce qui diminue le nombre d’instructions assembleur
  • Le parseur AVX2, dépourvu de registres de masque, a une structure bien plus simple et s’est révélé en pratique plus rapide qu’AVX-512
  • Le nouveau parseur AVX-512-to-256 lit les données avec AVX-512 puis contourne entièrement le problème du traitement des masques via des instructions de conversion 256 bits ; son implémentation est plus simple et il dépasse 21 Go/s

Récapitulatif des benchmarks des différents parseurs

  • Les benchmarks comparant tous les types de parseurs via une variable d’environnement montrent que le parseur AVX-512-to-256 est le plus rapide avec 21,5 Go/s
  • Les parseurs basés sur AVX2 et Vector256 affichent aussi des performances très proches, à moins de 5 % d’écart
  • Les parseurs Vector128 et Vector512 sont 5 à 10 % plus lents qu’AVX2, et Vector512 est même plus lent que Vector128
  • Le parseur IndexOfAny est nettement plus lent que les autres parseurs SIMD. Vector64 n’étant pas accéléré sur le 9950X, ses performances sont très faibles
  • Les parseurs SIMD basés sur AVX-512 et AVX2 démontrent des performances écrasantes face aux parseurs CSV comparables

Benchmarks de haut niveau : comparaison 5950X vs 9950X

  • Sur une base de 1 million de lignes d’assets de packages, Sep_MT enregistre 72 ms (8 Go/s) sur le 9950X contre 119 ms (4,9 Go/s) sur le 5950X
  • Sur des données de charge réelle (float, etc.), le 9950X atteint également une bande passante multithread d’environ 8 Go/s
  • Le changement de génération (5950X→9950X) apporte un gain d’environ 1,5 à 1,6x en parsing applicatif réel
  • Face aux bibliothèques CSV concurrentes (Sylvan, ReadLine, CsvHelper, etc.), Sep démontre un débit de traitement nettement supérieur et une allocation de ressources minimale

Conclusion et résumé

  • Sep 0.10.0 repousse les limites des performances du parsing CSV en combinant optimisations logicielles et fonctionnalités matérielles récentes (AVX-512, fréquence élevée)
  • La clé de cette avancée réside dans la conception de nouveaux algorithmes SIMD, ainsi que dans l’amélioration du code JIT .NET et de la structure assembleur
  • L’effet cumulé des gains de performance progressifs et du changement de génération d’architecture sur une courte période est particulièrement impressionnant
  • Dans le domaine du parsing CSV, Sep s’impose concrètement comme une solution de très haute performance, multiplateforme et extensible

1 commentaires

 
GN⁺ 2025-05-11
Commentaires sur Hacker News
  • Il est assez absurde qu’Intel ait investi pendant des années, jusqu’à y consacrer de la surface de puce, pour prendre en charge AVX-512 sur ses produits grand public, puis l’ait retiré des SKU grand public précisément au moment où les bibliothèques commençaient enfin à l’utiliser de plus en plus. Ce n’est pas qu’AMD fasse mieux pour la prise en charge d’AVX-512 ; c’est juste qu’Intel a abandonné ce dans quoi il avait lui-même investi, ce qui a ironiquement ouvert la voie à AVX-512 sur les CPU grand public d’AMD.
    • Intel répète toujours le même schéma : créer un marché technologique (Optane), puis se retirer brusquement (Depth Cameras), au grand désarroi des consommateurs. Ils misent tout d’un coup sur une nouvelle techno, puis arrêtent immédiatement si l’adoption ne suit pas. Le support d’Optane a été interrompu au moment même où il commençait à arriver à maturité dans le noyau Linux. Il y a aussi leurs étranges stratégies de réduction des coûts. Quand on remonte dans l’histoire, ils répètent les mêmes erreurs depuis l’Intel iAPX 432.
    • Dans cet article, sur un CPU AMD, on observe : original : 18GB/s, AVX2 : 20GB/s, AVX512 : 21GB/s. AVX-512 n’apporte presque rien par rapport à AVX2. Les CPU grand public d’Intel prennent aussi en charge AVX2 sur les E-cores, et le benchmark est mono-thread. Intel a retiré AVX-512 de la puce pour mettre davantage de cœurs, ce qui donne 24 cœurs au sommet de gamme, contre 16 chez AMD. Comme l’écart AVX2 → AVX512 est minime, en multithread c’est potentiellement le camp avec le plus de cœurs qui l’emporte. Dans la majorité des charges réelles, l’augmentation du nombre de cœurs apporte plus qu’AVX-512. À part quelques tâches très spécifiques, je pense que la décision d’Intel était raisonnable.
    • AVX-10 arrive bientôt, avec apparemment des capacités très proches d’AVX-512 (je ne sais pas non plus exactement ce qui change).
    • Le point le plus intéressant dans cet article, pour moi, c’est que sur l’AMD 9950X, le parseur AVX2 était environ 10 % plus rapide que le parseur basé sur AVX-512 (20GB/s contre 21GB/s). Au final, AVX-512 ne semble pas très utile pour le consommateur moyen. Si l’analyse CSV atteint déjà 20GB/s, je n’ai pas à me plaindre. Seuls les passionnés d’assembleur semblent vraiment sensibles à sa présence ou non.
    • C’est vraiment sidérant de voir Intel agir aussi stupidement.
    • Pour te rassurer, Sep utilise AVX-512 dès qu’il le peut, sans configuration particulière. Ça fonctionne bien dans un runtime JIT, donc même si tu vises involontairement le plus petit dénominateur commun en matière de performances, tu n’y perds pas vraiment.
    • Intel n’est pas très bon non plus sur le support logiciel. L’iGPU de mon portable est pourtant assez correct, mais il est mal pris en charge par PyTorch et d’autres outils, ce qui est frustrant. llama.cpp et l’inférence Vulkan marchent bien, donc j’aimerais que d’autres logiciels offrent un support du même genre.
  • Au lieu de faire quatre comparaisons par caractère ('\n', '\r', ';', '“') suivies de trois opérations or, on peut utiliser une astuce classique : un seul shuffle, une seule comparaison et zéro opération or. J’ai présenté cette technique dans un billet de blog, si ça intéresse. Cela dit, dans cet article aussi, ils ont réduit les opérations or avec vpternlogd et vpor.
  • C’est vraiment pénible qu’Intel ait décidé de mettre des cœurs lents dans ses CPU grand public et de retirer complètement AVX-512 sans même envisager le « multi-pumping ».
    • La cause principale de ce choix, ce sont les problèmes du procédé 10nm. Le rendement était mauvais et le coût beaucoup trop élevé, donc ils ont essayé de découper les puces au maximum et de rentabiliser avec des cœurs de type Atom et un marketing basse consommation. Sur le haut de gamme, ils ont augmenté la taille et réduit les marges pour défendre le marché serveur/cloud. Au final, la rentabilité a baissé et ils ont quand même perdu des parts de marché, mais ils ont au moins essayé.
  • L’affirmation d’un gain d’environ 3x en vitesse en deux ans depuis la sortie de Sep (juin 2023) est discutable si l’on tient compte aussi du saut matériel.
    • À matériel identique, l’amélioration logicielle (0.9.0 à 0.10.0) est de 17 %, et si on ajoute 17 % à 13088 pour la 0.9.0, on obtient 15375 ; comparé à 7335 pour la 0.1.0, cela fait environ 2,1x d’amélioration.
    • Ils affirment un gain de 3GB/s par rapport à une ancienne version de sep sur le même matériel, et les vitesses réelles ainsi que les informations matérielles sont documentées de manière transparente.
    • Nous ne sommes plus vraiment à l’époque de la loi de Moore, donc il est difficile d’attendre un gain de 3x dû uniquement au matériel. Même cela reste, à mes yeux, un résultat très impressionnant aujourd’hui.
    • Il y a clairement matière à débat si l’on annonce une amélioration de 3x sans prendre en compte le saut matériel, mais cela reste intéressant comme façon d’observer les performances logicielles réelles d’une année sur l’autre.
    • Le graphique de benchmark saute carrément quatre générations de CPU avant de faire apparaître soudainement une « énorme amélioration de performance », donc je ne lui fais pas confiance.
  • J’espère qu’Arthur Whitney sera stimulé par ce résultat et le dépassera avec une ligne de code, ou qu’il battra le record en une ligne avec une mise à jour du moteur shakti, ou bien qu’on aura une mise à jour de l’actualité. J’attends la suite avec intérêt.
  • Rien que penser à qui doit traiter dix millions de lignes de CSV à cette vitesse me donne le vertige.
    • J’ai déjà vécu ça moi aussi. Au départ, on choisit CSV parce que le volume de données est faible, que c’est facile à lire pour les non-développeurs — surtout ceux qui maîtrisent bien Excel — et que ça permet de gérer proprement des logs/processus. Mais quand les volumes sont multipliés par 10 ou 100, il devient concrètement nécessaire d’optimiser l’ingestion de CSV contenant des centaines de millions, voire des milliards de lignes. Ce genre d’optimisation permet surtout de gagner du temps pour migrer progressivement les processus internes vers un format plus adapté.
    • CSV est en fait un format interne plus courant qu’on ne le pense, avec l’avantage supplémentaire d’être facile à compresser (deflate). J’ai déjà travaillé sur du code qui crachait des données Netflow en CSV au débit d’une carte NIC. Personnellement, si le traitement devient aussi complexe, je me dis qu’on ferait mieux d’utiliser protocol buffers à la place. protobuf n’est pas un format si difficile, et pourtant son adoption peine à décoller.
    • Ce qui me fait encore plus peur, c’est de devoir stocker le résultat d’un traitement CSV à 21GB/s. Même si les agrégations sont utiles, à cette vitesse il faut bien que tout cela s’accumule quelque part, ce qui soulève des questions.
    • Malgré tous ses défauts, je pense que CSV reste encore aujourd’hui le format d’échange de données le plus courant.
    • Dans la finance, tout le monde peut partager du CSV, et comme c’est du texte, on peut l’envoyer n’importe où et le traiter facilement.
    • On peut prendre comme exemple le fichier de produit cartésien que le service comptable envoie en fin d’année.
    • En pratique, je galère justement parce que je dois manipuler ce genre de CSV à l’ancienne.
    • Dans presque tous les cas, HDF5 est meilleur que CSV. Et pourtant, il est difficile de l’expliquer autrement que par l’ignorance, la paresse ou le simple « ça marche comme ça ».
  • Je m’attendais à voir du code assembleur, et j’ai été surpris et impressionné que ce soit du C#. Très beau résultat.
    • Les versions récentes de .NET sont le « langage de haut niveau » qui intègre le plus profondément SIMD et les intrinsics vectoriels. Tanner Gooding de Microsoft a largement contribué à ces avancées, et ses billets de blog sur le sujet sont excellents.
  • Ce qui est déroutant, c’est que le texte principal ne définit pas clairement ce que fait exactement le code à 21GB/s. Par exemple, le format analysé n’est pas précisé en détail (gestion des guillemets dans le CSV, etc.), ni la façon dont le résultat est utilisé après l’analyse (insertion dans une structure de données, etc.).
    • Les ns/row calculées dans l’article tournent autour de 27ns/row (environ 37 000 lignes par seconde), mais si c’était vraiment 21GB/s, cela ferait environ 570KB par ligne, ce qui ressemble à un benchmark très anormal.
  • D’après mon expérience, il est difficile d’obtenir un gros gain avec du code SIMD personnalisé par rapport à l’auto-vectorisation des compilateurs modernes, surtout sur du code naturellement favorable à la vectorisation. Les cas particuliers comme le parsing JSON sont un peu différents.
  • J’ai récemment travaillé sur un export CSV de 300GB, et la manipulation ainsi que la vérification d’intégrité prennent énormément de temps ; un parseur CSV rapide comme celui-ci est donc vraiment nécessaire.
    • Je ne comprends pas pourquoi on n’utilise pas un format spécialisé pour stocker des données en virgule flottante. HDF5 est une bien meilleure alternative.