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

Commandes pas à jour, on dirait qu'un certain LPx a fait du renaming sans changer la doc… :-P Voir Commit 2015-08-25

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)

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é

Il serait possible d'ajouter un paramètre à la batterie (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