3. Quelques conseils préalables#
On formule ici quelques conseilspour aider l’utilisateur à tirer parti des stratégies de calcul parallèle du code . Mais il faut bien être conscient, qu’avant tout chose, il faut d’abord optimiser et valider son calcul séquentiel en tenant compte des conseils qui fourmillent dans les documentations des commandes. Pour ce faire, on utilise, si possible, un maillage plus grossier et/ou on n’active que quelques pas de temps.
Le paramétrage par défaut et les affichages/alarmes du code proposent un fonctionnement équilibré et instrumenté . On liste ci-dessous et, de manière non exhaustive, plusieurs questions qu’il est intéressant de se poser lorsqu’on cherche à paralléliser son calcul. Bien sûr, certaines questions (et réponses) sont cumulatives et peuvent donc s’appliquer simultanément.
3.1. Préambule#
Il est intéressant de valider , au préalable, son calcul parallèle en comparant quelques itérations en mode séquentiel et en mode parallèle. Cette démarche permet aussi de calibrer les gains maximums atteignables (speed-up théoriques) et donc d’éviter de trop «gaspiller de processeurs». Ainsi, si on note \(f\) la portion parallèle du code (déterminée par exemple via un run séquentiel préalable), alors le speed-up théorique S p maximal accessible sur p processeurs se calcule suivant la formule d’Amdhal (cf. [R6.01.03] §2.4) :
\({S}_{p}=\frac{1}{1-f+\frac{f}{p}}\)
Par exemple, si on utilise le parallélisme MUMPS distribué par défaut (scénario 1b+2b) et que les étapes de construction/résolution de système linéaire représentent 90% du temps séquentiel ( f =0.90), le speed-up théorique est borné à la valeur \({\mathrm{S}}_{\infty}=\frac{1}{1-0.9+0.9/\infty }=10\) ! Et ce, quelque soit le nombre de processus MPI alloués.
Il est intéressant d’évaluer les principaux postes de consommation (temps/RAM) : en mécanique quasi-statique, ce sont généralement les étapes de calculs élémentaires/assemblages , de résolution de système linéaire et les algorithmes de contact-frottement . Mais leurs proportions dépendent beaucoup du cas de figure (caractéristiques du contact, taille du problème, complexité des lois matériaux…). Si les calculs élémentaires sont importants, il faut les paralléliser via la scénario 1b (scénario par défaut). Si, au contraire, les systèmes linéaires focalisent l’essentiel des coûts, les scénarios 2b ou 2c peuvent suffire. Par contre, si c’est le contact-frottement qui dimensionne le calcul, il faut chercher à optimiser son paramétrage et/ou paralléliser son solveur linéaire interne (cf. méthode GCP+MUMPS).
En dynamique, si on effectue un calcul par projection sur base modale, cela peut être cette dernière étape qui s’avère la plus coûteuse. Pour gagner du temps, on peut alors utiliser l’opérateur CALC_MODES avec l’option “BANDE” découpée en plusieurs sous-bandes, en séquentiel et, surtout, en parallèle (scénario 1d). Cet opérateur exhibe une distribution de tâches quasi-indépendantes qui conduit à de bons speedups.
Pour optimiser son calcul parallèle, il faut surveiller les éventuels déséquilibres de charge du flot de données (CPU et mémoire) et limiter les surcoûts dus aux déchargements mémoire (JEVEUX et MUMPS OOC) et aux archivages de champs . Sur le sujet, on pourra consulter la documentation [U1.03.03] «Indicateur de performance d’un calcul (temps/mémoire)». Elle indique la marche à suivre pour établir les bons diagnostics et elle propose des solutions.
Pour CALC_MODES avec l’option “BANDE” découpée en plusieurs sous-bandes, le respect du bon équilibrage de la charge est crucial pour l’efficacité du calcul parallèle : toutes les sous-bandes doivent comporter un nombre similaire de modes. On conseille donc de procéder en trois étapes:
Calibrage préalable de la zone spectrale par des appels à INFO_MODE(si possible en parallèle),
Examen des résultats,
Lancement en mode POURSUITE du calcul CALC_MODES, avec l’option “BANDE” découpée en plusieurs sous-bandes parallélisées.
Pour plus de détails on pourra consulter la documentation utilisateur de l’opérateur[U4.52.02].
3.2. Quelques chiffres empiriques#
On conseille d’allouer au moins 30 à 50.103 ddls par processus MPI (scénarios 1b, 2b ou 2c). Cette granularité peut descendre à quelques milliers de ddls par threads OpenMP tout en restant efficace (scénarios 1c ou 2a).
Un calcul thermo-mécanique standard bénéficie généralement, sur 32 processeurs, d’un gain de l’ordre de la dizaine en temps elapsed et d’un facteur 4 en pic mémoire RAM (par cœur).
Pour CALC_MODES, on conseille de décomposer son calcul en sous-bandes de quelques dizaines de modes (par exemple 60) et, ensuite, de prévoir 2, 4 voire 8 processus MUMPS par sous-bande. Il faut bien sûr composer avec le nombre de processeurs disponibles et le pic mémoire requis par le problème [8]_ .
On peut obtenir des gains d’un facteur 30, en temps elapsed, sur une centaine de processeurs. Les gains en mémoire sont plus modestes (quelques dizaines de pourcents).
L’étape de calibration modale via INFO_MODE ne coûte elle pratiquement rien en parallèle: quelques minutes, tout au plus, pour des problèmes de l’ordre du million d’inconnus, parallélisés sur une centaine de processeurs. Les gains en temps sont d’un facteur X70 sur une centaine de processeurs et jusqu’à x2 en pic mémoire RAM.
3.3. Calculs indépendants#
Lorsque la simulation que l’on souhaite effectuer se décompose naturellement (étude paramétrique, calcul de sensibilité…) ou, artificiellement (chaînage thermo-mécanique particulier…), en calculs similaires mais indépendants, on peut gagner beaucoup en temps calcul grâce au parallélisme numérique 1a.
3.4. Gain en mémoire RAM#
Lorsque le facteur mémoire dimensionnant concerne la résolution de systèmes linéaires (ce qui est souvent le cas), le cumul des parallélismes informatiques 1b (calculs élémentaires/assemblages) et numériques 2b (solveur linéaire distribué MUMPS) est tout indiqué [9]_ (voire 1b+2b/1c).
Une fois que l’on a distribué son calcul Code_Aster +MUMPS/PETSC sur suffisamment de processeurs, les consommations RAM de JEVEUX peuvent devenir prédominantes (par rapport à celles de MUMPS que l’on a étalées sur les processeurs). Pour rétablir la bonne hiérarchie (le solveur externe doit supporter le pic de consommation RAM !) il faut activer, en plus, l’option SOLVEUR/MATR_DISTRIBUEE [U4.50.01].
Pour résoudre des problèmes frontières de très grandes tailles (> 5M ddls), on peut aussi essayer les solveurs itératifs de PETSC (stratégie parallèle 2c ou 2b+2c).
3.5. Gain en temps#
Si l’essentiel des coûts concerne uniquement les résolutions de systèmes linéaires de petite taille (N<0.5M ddls) on peut se contenter d’utiliser les solveurs linéairesMUMPS en mode centralisé (stratégie 2b) ou MULT_FRONT (2a). Dès que la construction des systèmes devient non négligeable (>5%) ou que ceux-ci s’avèrent assez gros, il est primordial d’étendre le périmètre parallèle en activant la distribution des calculs élémentaires/assemblages (1b) et en passant à MUMPS distribué (valeur par défaut).
Sur des problèmes frontières de grandes tailles (N>3M ddls), une fois les bons paramètres numériques sélectionnés [10]_ (préconditionneur, relaxation… cf. [U4.50.01]), les solveurs itératifs parallèle (2c) peuvent procurer des gains en temps très appréciables par rapport aux solveurs directs génériques (2a/2b). Surtout si les résolutions sont relaxées [11]_ car, par la suite, elles sont corrigées par un processus englobant (algorithme de Newton de THER/STAT_NON_LINE…).
Pour les gros problèmes modaux (en taille de problème et/ou en nombre de modes), il faut bien sûr penser à utiliser CALC_MODES avec l’option “BANDE” découpée en plusieurs sous-bandes [12]_ .