- Une validation expérimentale du déséquilibre entre les performances d’I/O et la vitesse de traitement du CPU récemment discuté montre qu’en pratique, le CPU reste la principale contrainte
- La vitesse de lecture séquentielle atteint 1,6 Go/s avec un cache froid et 12,8 Go/s avec un cache chaud, mais le calcul de fréquence des mots sur un seul thread reste autour de 278 Mo/s
- La structure en branches du code empêche la vectorisation, et même une simple optimisation de conversion en minuscules n’améliore les performances qu’à environ 330 Mo/s
- Même la commande
wc -w ne atteint que 245 Mo/s, ce qui confirme que le calcul CPU et le traitement des branches, plutôt que le disque, constituent le goulot d’étranglement
- Une vectorisation manuelle basée sur AVX2 a permis d’atteindre 1,45 Go/s, mais cela ne représente encore qu’environ 11 % de la vitesse de lecture séquentielle, ce qui prouve que le CPU, et non l’I/O, est le goulot d’étranglement
Comparaison entre vitesse d’I/O et performances CPU
- En suivant l’affirmation de Ben Hoyt, une expérience a été menée pour vérifier si la récente hausse de la vitesse de lecture séquentielle avait dépassé la stagnation des performances CPU
- Mesuré de la même manière, le résultat est de 1,6 Go/s avec cache froid et 12,8 Go/s avec cache chaud
- Pourtant, le calcul de fréquence des mots sur un seul thread n’atteint que 278 Mo/s
- Même avec un cache chaud, cela représente environ un cinquième de la vitesse de lecture du disque
Expérience de calcul de fréquence des mots en C
- Avec GCC 12,
optimized.c a été compilé avec les options -O3 -march=native, puis exécuté sur un fichier d’entrée de 425 Mo
- Résultat : 1,525 seconde, soit un débit de 278 Mo/s
- Les multiples branches dans le code et les sorties anticipées empêchent les optimisations de vectorisation du compilateur
- Après avoir déplacé la logique de conversion en minuscules hors de la boucle, le débit est monté à 330 Mo/s
- Avec Clang, la vectorisation est mieux réalisée
Comparaison avec un simple comptage de mots (wc -w)
- Exécution de la commande
wc -w, qui compte seulement le nombre de mots au lieu de calculer leur fréquence
- Résultat : 245,2 Mo/s, plus lent que prévu
wc traite divers caractères d’espacement comme ' ', '\n', '\t', ainsi que des caractères dépendants de la locale
- Il effectue donc davantage d’opérations qu’un code qui ne distingue que l’espace simple
Tentative de vectorisation basée sur AVX2
- Mise en œuvre d’une vectorisation avec le jeu d’instructions AVX2 en exploitant les fonctionnalités des CPU récents
- Utilisation de registres 256 bits et alignement des données sur 32 bits
- Utilisation de l’instruction
VPCMPEQB pour comparer les caractères d’espacement
- Détection des frontières de mots à l’aide d’un masque de bits (
PMOVMSKB) et de l’instruction Find First Set (ffs)
- Inspiré de l’implémentation de
strlen dans Cosmopolitan libc
Résultats de performance et conclusion
- Le code vectorisé manuellement (
wc-avx2) atteint un débit de 1,45 Go/s
- Vérification effectuée avec le même résultat que
wc -w (82,113,300 mots)
- Même avec un cache froid, le temps de calcul en mode user reste dominant
- Cela confirme que le calcul CPU est le goulot d’étranglement, plus encore que l’I/O disque
- Globalement, la vitesse du disque est suffisante, mais le traitement des branches et les calculs de hachage côté CPU restent les facteurs limitants
- Le code et les résultats expérimentaux sont publiés sur GitHub (
haampie/wc-avx2)
Aucun commentaire pour le moment.