Exemple de tests de scalabilité avec la MKL (en mémoire partagée)
Article mis en ligne le 15 juillet 2014
dernière modification le 20 septembre 2017
logo imprimer

Dans cet article nous testons la performance de la parallélisation et du placement des processus sur la routine SGEMM de la MKL dans sa version multithreadée.

Nous traitons ici différents cas, puisque nous faisons varier aussi bien la taille de la matrice carrée (5000, 10000, 25000 et 50000 lignes/colonnes), que le nombre de cores sur lequel est lancé ce calcul : 1 core (=sequentiel), 5 cores, 10 cores, 20 cores, 40 cores (=hyperthreading).


Dans l’environnement par défaut

Squelette du script testé dans l’environnement par défaut :

On s’intéresse au speed up de ce calcul, à savoir le ratio du temps de calcul en séquentiel (=sur 1 core) sur le temps de calcul en parallèle sur n cores :

Sp=Tséquentiel/Tparallèle

Plus ce ratio se rapproche du nombre de cores utilisés pour le calcul parallèle, plus l’efficacité parallèle de ce code est bonne. Par exemple : si avec 10 cores on va dix fois plus vite qu’en séquentiel, alors le speed up vaut 10 et il est donc idéal.

Pour l’exemple traité ici, le speed up a été calculé sur la base des temps de restitution ci-dessous :

TEMPS DENombre de lignes/colonnes de la matriceSPEED UPNombre de lignes/colonnes de la matrice
RESTITUTION5000100002500050000ASSOCIE5000100002500050000
Nombre de cores 1 6,54 47,53 738,05 5886 Nombre de cores 1 / / / /
5 2,11 10,50 149,85 1190 5 3,11 4,53 4,93 4,95
10 0,85 5,47 75,36 598 10 7,74 8,69 9,79 9,84
20 0,96 5,12 61,81 444 20 6,79 9,29 11,94 13,25
40 1,39 4,32 52,17 410 40 4,69 11,01 14,15 14,34
Courbe de scalabilité (ou courbe d’extensibilité) :

courbe affichant le speed up en fonction du nombre de cores sur lequel est lancé le calcul




Ci-contre la courbe de scalabilité associée au code calculant le résultat d’un multiplication de deux matrices carrées non vides de différentes tailles (5000, 10000, 25000 et 50000 lignes/colonnes).

On peut voir que pour 5 cores (et 10 cores respectivement), quelque soit la taille du problème, le speed up est très bon puisqu’il est très proche de 5 (et 10 respectivement).

Par contre pour le problème de taille 5000, augmenter encore le nombre de cores sur lequel est lancé le calcul dégrade le speed up. La scalabilité dépend donc de la taille du problème étudié.
(En rouge : le speed up idéal)

En plaçant la variable : OMP_PROC_BIND=true

Cette variable assure que lorsqu’une tâche est lancée sur un cpu, elle reste bien sur celui-ci. De plus, elle répartie les tâches uniquement sur les cores physiques, et dans l’ordre. Ainsi pour un nombre de tâches égal à 10, les threads occuperont les cores de 0-9.
Les temps de restitution que nous obtenons alors sont les suivants :

TEMPS DENombre de lignes/colonnes de la matriceGAINNombre de lignes/colonnes de la matrice
RESTITUTION5000100002500050000RELATIF5000100002500050000
Nombre de cores 1 6,39 47,98 737,37 5910 Nombre de cores 1 2% -1% 0% 0%
5 1,92 9,99 149,43 1191 5 9% 5% 0% 0%
10 1,40 5,52 75,51 595 10 -65% -1% 0% 1%
20 0,85 3,56 38,60 302 20 12% 30% 38% 32%
40 0,76 4,21 63,47 533 40 45% 2% -22% -30%

Pour le problème de petite taille (n=m=5000), les temps de restitutions sont très faibles (<2s) et varient d’un job à un autre, ce qui empêche de tirer une conclusion claire.

Pour les problèmes de plus grandes tailles (n=m=25000 et 50000), on voit que lorsqu’on utilise moins de la moitié du nœud (nombre de cores < ou = à 10), sans spécifier de placement particulier, les tâches se répartissent "naturellement" sur des cores différents. Lorsqu’on les place avec l’option OMP_PROC_BIND, cette répartition est plus "propre", mais ne change pas les temps de calcul.

Par contre lorsqu’on utilise la totalité du nœud sans spécifier de placement, certaines tâches vont se placer sur des cores physiques et leur core logique associé, créant de l’hyperthreading. Avec l’option OMP_PROC_BIND toutes les tâches sont placées sur les cores physiques, et on gagne systématiquement 30% de temps de calcul (pour cet exemple) et on améliore grandement le speed up. Pour les problèmes de grandes tailles, il est presque idéal : lorsqu’on fait tourner un job sur x cores, il va x fois plus vite qu’en séquentiel (sauf en hyperthreading).

SPEED UPNombre de lignes/colonnes de la matrice
ASSOCIE5000100002500050000
Nombre de cores 1 / / / /
5 3,33 4,80 4,93 4,96
10 4,57 8,69 9,76 9,94
20 7,51 13,49 19,10 19,56
40 8,36 11,40 11,62 11,09
1/ En pointillés : speed up précédent

2/ En traits pleins : speed up avec la variable OMP_PROC_BIND=true
3/ 40 cores = 20 cores physiques + 20 cores logiques (hyperthreadés)


Site réalisé sous SPIP
avec le squelette ESCAL-V3
Version : 3.86.44
Hébergeur : INP Toulouse