AMD 9950X atteint 21 Go/s en parsing CSV avec SIMD
(nietras.com)- Sep 0.10.0 atteint 21 Go/s en parsing CSV bas niveau grâce à des optimisations pour les CPU compatibles AVX-512 comme l’AMD 9950X (Zen 5), contre environ 18 Go/s auparavant
- Le gain de performance vient d’une restructuration du parser pour réduire le goulot d’étranglement lié aux allers-retours des registres de masque dans la génération de code AVX-512 de .NET 9.0
- Le nouveau parser AVX-512-to-256 charge les
charen 512 bits puis les convertit en vecteurs d’octets 256 bits, évitant le traitement des masques et le coût d’une permutation séparée - Les performances de parsing bas niveau de Sep se sont améliorées d’environ 3×, passant d’environ 7 Go/s avec la version 0.1.0 en 2023 sur 5950X/.NET 7.0 à environ 21 Go/s avec la version 0.10.0 sur 9950X/.NET 9.0
- Dans les benchmarks de plus haut niveau, Sep multithread sur 9950X traite aussi 1 million de lignes de package assets en 72,213 ms, soit environ 8,0 Go/s, et les données floats atteignent également environ 8,1 Go/s
Objectifs et résultats de Sep 0.10.0
- Sep 0.10.0 est sorti le 22 avril 2025 et inclut des optimisations pour les CPU compatibles AVX-512 comme l’AMD 9950X (Zen 5), ainsi que des benchmarks sur 9950X
- En parsing CSV bas niveau, Sep atteint 21 Go/s sur 9950X
- Avant la version 0.10.0, il était à environ 18 Go/s sur le même 9950X
- L’analyse porte sur le parsing bas niveau
Rowsde données CSV package assets, et tous les chiffres sont en monothread - Les chiffres de benchmark peuvent varier de quelques points de pourcentage, de petites régressions pouvant donc apparaître sur certaines releases
Évolution des performances de 0.1.0 à 0.10.0
- Les performances de Sep se sont progressivement améliorées sous l’effet combiné des changements de code, des versions de .NET et des générations de CPU
- La progression représentative est la suivante
- 0.1.0, 5950X, .NET 7.0 : environ 7 Go/s
- 0.3.0, 5950X, .NET 8.0 : environ 12 Go/s
- 0.6.0, 5950X, .NET 9.0 : environ 13 Go/s
- 0.9.0, 9950X, .NET 9.0 : environ 18 Go/s
- 0.10.0, 9950X, .NET 9.0 : environ 21 Go/s
- Depuis la publication de Sep en juin 2023, il est devenu environ 3× plus rapide en un peu moins de deux ans
- En comparant Sep 0.9.0 sur 5950X à Sep 0.10.0 sur 9950X, l’amélioration est d’environ 1,6×
- La fréquence boost du 9950X est de 5,7 GHz, contre 4,9 GHz pour le 5950X
- Cet écart de fréquence est considéré comme pouvant expliquer à lui seul un facteur d’environ 1,2×
Goulot d’étranglement des registres de masque dans la génération de code AVX-512 de .NET
- Sep prend en charge AVX-512 depuis la version 0.2.3, mais .NET 8 ne prenait alors pas explicitement en charge les registres de masque
k1-k8d’AVX-512 - Dans l’ancienne génération de code AVX-512, le résultat d’une comparaison était placé dans un registre de masque, puis transféré vers un registre général, avant de revenir dans un registre de masque
- Après la mise à niveau vers le 9950X, Sep 0.9.0 a atteint environ 18 Go/s en parsing CSV bas niveau, soit environ 1,4× plus rapide que sur 5950X
- En changeant de parser via une variable d’environnement pour comparer, le parser AVX2 a atteint environ 20 Go/s sur 9950X, soit environ 10 % de plus que l’ancien parser AVX-512
- Cet écart a confirmé que le traitement des registres de masque AVX-512 continuait d’affecter les performances
Structure de base de la boucle de parsing de Sep
- Tous les parsers de Sep suivent la même structure de base, avec une méthode générique
Parseunique qui prend en charge deux chemins selon que les guillemets doivent être traités ou nonParseColInfos: utilisé lorsque les guillemets sont traités, avec davantage de suivi d’état nécessaireParseColEnds: utilisé lorsqu’il n’y a pas de traitement des guillemets
- Le parsing s’effectue par spans de
charissus d’un tableau, avec une taille de 16K dans l’exemple- Cette taille est assez petite pour tenir dans le cache CPU, et elle est aussi favorable à un multithreading efficace ensuite
- La boucle charge des données de caractères 16 bits dans des registres SIMD, les convertit en registres SIMD d’octets, puis compare les caractères spéciaux CSV
- Les cibles de comparaison incluent
\n,\r,",;, etc.
- Les cibles de comparaison incluent
- Le résultat de la comparaison est converti en bitmask, puis seuls les bits définis dans le masque sont parsés séquentiellement
- Les écarts de performance dépendent fortement de la façon dont ce code C# SIMD est compilé JIT en code machine par .NET
Ancien parser AVX-512 et ajustements de la version 0.10.0
- Le
SepParserAvx512PackCmpOrMoveMaskTzcntde la version 0.9.0 charge 32chardans chacun de deux registres SIMD 512 bits, puis les compacte en un vecteur d’octets 512 bits afin de traiter 64 caractères par boucle - Les données compactées étant dans un ordre mélangé, elles doivent être réordonnées avec
PermuteVar8x64 - Dans l’assembleur produit par .NET 9.0, chaque
Vec.Equalsse traduisait par deux instructions,vpcmpeqbetvpmovm2b, avec des transferts répétés entre les registres de masque commek1et les registres vectoriels générauxzmm - Dans Sep 0.10.0, l’appel à
MoveMaskest avancé afin de réduire le nombre d’allers-retours entre registres de masque et registres généraux- Dans les autres parsers,
MoveMaskn’est appelé qu’en cas de besoin afin de réduire le nombre d’instructions sur le chemin rapide « sans caractères spéciaux »
- Dans les autres parsers,
- Même après cet ajustement, le transfert depuis le registre de masque vers le registre général demeure, mais le nombre total d’instructions assembleur diminue
AVX2 et nouveau parser AVX-512-to-256
- L’assembleur du
SepParserAvx2PackCmpOrMoveMaskTzcntbasé sur AVX2 a une structure plus directe, car il n’utilise pas de registres de masque - Grâce à cette structure, le parser AVX2 était plus rapide que l’ancien parser AVX-512 de la version 0.9.0
- Le nouveau
SepParserAvx512To256CmpOrMoveMaskTzcntde la version 0.10.0 charge lescharavec des instructions AVX-512, puis crée un vecteur d’octets 256 bits avecConvertToVector256ByteWithSaturation- L’instruction réelle est
vpmovuswb - Le débit par boucle n’est « que » de 32
char, mais la structure est plus simple
- L’instruction réelle est
- Cette approche évite le problème des registres de masque 512 bits, et les données compactées sont déjà dans le bon ordre dans
ymm4, sans permutation séparée nécessaire - Le nouveau parser porte les performances de parsing de Sep à environ 21 Go/s sur 9950X
Benchmarks bas niveau par parser sur 9950X
- En exécutant tous les parsers via des variables d’environnement sur AMD 9950X, le nouveau parser AVX-512-to-256 s’est révélé le plus rapide
- Les principaux résultats sont les suivants
SepParserAvx512To256CmpOrMoveMaskTzcnt: 21597,7 Mo/s, 27,0 ns/ligne, 1,351 msSepParserVector256NrwCmpExtMsbTzcnt: 20608,5 Mo/s, 28,3 ns/ligne, 1,416 msSepParserAvx2PackCmpOrMoveMaskTzcnt: 20599,3 Mo/s, 28,3 ns/ligne, 1,417 msSepParserAvx512PackCmpOrMoveMaskTzcnt: 19944,3 Mo/s, 29,3 ns/ligne, 1,463 ms
- Le parser multiplateforme basé sur
Vector256atteint presque le même niveau qu’AVX2 - Les parsers multiplateformes basés sur
Vector128etVector512restent rapides, mais sont 5 à 10 % plus lents, etVector512est plus lent queVector128 SepParserIndexOfAnyest nettement à la traîne avec 2787,0 Mo/s, tandis queVector64n’est pas accéléré sur 9950X et reste à 459,9 Mo/s
Benchmarks de plus haut niveau sur 5950X et 9950X
- Sur les données package assets, le traitement de 1 million de lignes est nettement plus rapide sur 9950X que sur 5950X
- 5950X
Sep_MT: 119,430 ms, 4888,1 Mo/s - 9950X
Sep_MT: 72,213 ms, 8084,1 Mo/s
- 5950X
- Sur 9950X,
Sepen monothread traite 1 million de lignes package assets en 291,979 ms, soit 1999,4 Mo/s - Dans le même benchmark package assets sur 9950X, les solutions comparées affichent les performances suivantes
Sylvan: 413,265 ms, 1412,6 Mo/sReadLine_: 377,033 ms, 1548,4 Mo/s, allocations 1991,04 MoCsvHelper: 1005,323 ms, 580,7 Mo/s
- Sur les données floats, Sep multithread sur 9950X traite également 25 000 lignes en 2,497 ms, soit 8136,8 Mo/s
- L’amélioration des benchmarks de plus haut niveau entre 5950X et 9950X est d’environ 1,5 à 1,6×, proche de celle observée dans les benchmarks bas niveau
Aucun commentaire pour le moment.