x87 Intel vs AMD

En développant divers tests de performances sur SSE2, AVX2 et les vieilles instructions x87, j’ai découvert un problème de performance avec les processeurs Intel. En présence de représentations spéciales (NaN, +Inf, -Inf), les processeurs Intel (Core i5-4460 de microarchitecture Haswell et Celeron J1900 de microarchitecture Atom/Bay Trail) verront un ralentissement de leurs calculs par un facteur 300 environ, alors que les processeurs AMD récents (Ryzen 1700X, Ryzen 3600) ne verront aucune dégradation de performances par rapport aux mêmes calculs sur des représentations non spéciales. Même si cela se voit très bien dans du code C, on peut aussi en voir l’impact avec du code R, notamment avec des NA.

> v=double(1e5) # sur Ryzen 1700 (Windows 10)
> system.time(for(i in 1:1e4)sum(v))
   user  system elapsed 
   1.51    0.00    1.51
> v[1]=NA;system.time(for(i in 1:1e4)sum(v))
   user  system elapsed 
    1.5     0.0     1.5 

Ainsi, il faut 1.5 secondes pour qu’un Ryzen 1700 fasse les 1e5*1e4 = 1 milliard d’additions ; peu importe la présence de NA. Cela ne montre pas le pic de performance FP80, en raison du vecteur de grande taille (800 Ko) qui dépasse de la cache L1 et L2 des processeurs modernes.

Le même code sur Haswell (Windows 10) montre des résultats très différents:

> v=double(1e5) # sur core i5-4460 (Haswell)
> system.time(for(i in 1:1e4)sum(v))
   user  system elapsed 
   0.93    0.00    0.95 
> v[1]=NA;system.time(for(i in 1:1e4)sum(v))
   user  system elapsed 
 134.04    0.17  134.33

Ainsi, les performances sont environ 144 fois plus basses dès qu’il y a un NA au début du vecteur ! Le même problème est observé sur Celeron J1900 (Ubuntu 64 bits).

> v=double(1e5) # sur Celeron J1900 (Atom/Bay Trail)
> system.time(for(i in 1:1e4)sum(v))
utilisateur     système      écoulé
      2.908       0.000       2.901
> v[1]=NA;system.time(for(i in 1:1e4)sum(v))
utilisateur     système      écoulé
    135.600       0.012     135.416
>

Ce problème de performance avec les NA est observé pour sum(), mean(), rowSums(), rowMeans(), prod(), mais pas pour var() et sd() qui doivent détecter les NA avant de lancer les calculs. Ces problèmes disparaissent dès qu’on utilise le paramètre na.rm=TRUE.

Je n’ai pas accès à un CPU Intel vraiment récent, mais je crains que ce problème soit toujours présent (si vous pouvez tester et répondre en commentaire, je serais très intéressé de savoir). On peut se demander si ça pourrait venir d’une mauvaise gestion des Exception Flags x87 par Intel.

Je ne suis pas le seul à avoir remarqué ça.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *