Table of Contents
Calcul parallèle
Quand utiliser le parallélisme?
Metafor n'est pas complètement parallélisé. Néanmoins, il est possible d'effectuer certaines parties du calcul en parallèle (ALE et solveur linéaire actuellement).
Pour voir si votre test peut bénéficier du parallèle, il est utile d'aller jeter un oeil sur le fichier
workspace/votretest/timers.txt
Voila ce que ca donne par exemple:
user | real | kernel | omp | |
---|---|---|---|---|
GEN_EXT_FORC | 43.0095 | 43.848 | 0.0156001 | 43.9277 |
GEN_INERT_FORC | 93.117 | 93.723 | 0 | |
GEN_INTER_FORC | 247.059 | 250.334 | 0.0156001 | 250.814 |
Metafor | 2166.25 | 2229.01 | 6.33364 | 2233.16 |
buildK | 474.758 | 479.521 | 0.0156001 | 480.42 |
contactDetection | 95.0514 | 96.386 | 0.0156001 | 96.5679 |
prepro | 82.8209 | 90.388 | 0.436803 | 90.5551 |
solveK | 858.505 | 874.956 | 1.71601 | 876.568 |
Chaque colonne est un compteur du temps CPU. Regardons le compteur OpenMP (dernière colonne). On voit ici que le solveur (ligne “solveK
”) dure 876s sur les 2233s du calcul. En utilisant 2 CPUs, on peut diviser le temps solveur par un peu moins d'un facteur 2. on peut s'attendre donc à un gain CPU total de l'ordre de 438s sur ce test (ligne “Metafor
”).
Dans ce cas précis, c'est pas terrible mais si votre test est plus gros et que votre temps solveur avoisine les 90% du temps CPU total, ca peut valoir le coup de continuer à lire cette page…
Principe général
Il s'agit de parallélisation OpenMP. D'une part, une partie du code C++ de Metafor est parallélisé et, d'autre part, les opérations BLAS (y compris les solveurs parallèles MKL) utilisent également OpenMP.
Dans Metafor, les objets statiques Blas
et OpenMP
permettent de configurer le comportement d'OpenMP respectivement dans le code C++ et dans les routines Blas/MKL. Pour voir la config courante, il faut utiliser
OpenMP.status() Blas.status()
ceci est fait au démarrage de Metafor à titre informatif.
On peut aussi changer le nombre de threads utilisés par OpenMP en écrivant directement dans le jeu de données:
OpenMP.setNumThreads(n) Blas.setNumThreads(n)
où n
est le nombre de threads voulus. Il est également possible de ne configurer que Blas/MKL ou que le code C++.
Exécution dans un Metafor.exe
Les commandes précédentes s'écrivent simplement dans le jeu de données (n'importe où). Néanmoins, pour éviter de fixer définitivement le nombre de threads d'un modèle, il est possible de ne pas modifier le jeu de données et d'utiliser plutôt le flag “-j n” de Metafor.exe
:
Metafor.exe -j 2 -run montest
qui lance montest.py
avec 2 threads (C++ et Blas/MKL)
Par défaut, sans ce flag, le nombre de threads est toujours initialisé à 1 par Metafor.exe
, quelles que soient les valeurs des variables d'environement OpenMP et Blas/MKL.
Pourquoi? Simplement parce que les valeurs par défaut MKL et OpenMP ne sont pas identiques! Par exemple, sur une machine avec 4 coeurs hyperthreadés, on aura un nombre fixe de 8 threads pour le code OpenMP/C++ de Metafor alors que Blas/MKL en allouera un nombre variable entre 1 et 4 (en fonction de la charge machine!!).
Exécution sous python externe
Metafor peut également être lancé à l'aide d'un python.exe
traditionnel. C'est par exemple le cas de la batterie.
Dans ce cas particulier mais relativement courant, on est dans un environnement externe a priori inconnu (éventuellement même dans un autre programme qui possède une interface python!!). Aucune initialisation n'est donc effectuée pour ne pas interférer avec l'interpréteur inconnu. On se retrouve alors avec le comportement “classique” de OpenMP: le nombre de threads est fixé par la variable OMP_NUM_THREADS
et MKL_NUM_THREADS
. Par exemple:
set OMP_NUM_THREADS=n set MKL_NUM_THREADS=n set MKL_DYNAMIC=0 python montest2.py
lance montest2.py
, qui utilise Metafor, dans un interpréteur traditionnel avec les paramètres par défaut de Metafor. La variable MKL_DYNAMIC
permet d'avoir “n” threads Blas quelle que soit la charge de la machine.
Par défaut, on a donc le comportement qui peut sembler “bizarre” et qui est décrit ci-dessus où, sur une machine avec 4 coeurs hyperthreadés, tous les coeurs seront utilisés, mais de manière différente par le code C++ et la bibliothèque MKL.
En résumé
- Le nombre de threads utilisé par défaut pour
Metafor.exe
vaut 1 (pas de parallélisation) - Le nombre de threads est fixé par l'option “-j” de
Metafor.exe
- Sous python (et la batterie notamment), le nombre de threads n'est pas initialisé. Il peut être fixé
- soit via les variables d'environnement
(OMP_NUM_THREADS=n
,MKL_NUM_THREADS=n
,MKL_DYNAMIC=0
) - soit directement dans le jeu de données
(OpenMP.setNumThreads(n); Blas.setNumThreads(n);
)
battery.py
) pour spécifier le nombre de threads par test. Par exemple: “battery.py -j 4 -k 2
” pourrait par exemple lancer 4 tests en parallèle, chacun sur 2 CPUs…
— Romain BOMAN 2010/12/13 11:54