• Aucun résultat trouvé

J’ai commencé à m’intéresser à la programmation parallèle en février 2001, juste après l’obtention de mon poste de Chargé de Recherche au CNRS. C’est avec Annick Pouquet que nous avions imaginé faire un code parallèle où le domaine serait coupé en bâtonnet pour que les champs et les calculs puissent rentrer facilement dans le cache de la mémoire. Mais ce découpage n’a été finalement construit que très récem-ment. En effet, Annick Pouquet a pu avoir une copie du code hydrodynamique de Maurisse Meneguzzi et j’ai pu rapidement m’en inspirer pour construire mon propre code, avec un découpage du domaine en tranche (A.5.3). En 2002, j’ai obtenu un financement d’Action Incitative jeune chercheur du CNRS/SPI ( Science Physique pour l’ingénieur devenu l’INSIS) qui m’a permis de construire ma première ferme de calcul avec Patrick Michel («my officemate»). Nous avions acheté des PC (bi-processeurs) connectés avec un réseau à 100Mbytes/s dans un premiers temps, puis avec un passage au GBytes/s l’année d’après. Nous avions surnommé notre cluster «Madness» (voir Fig. A.11 ) . Nous étions les premiers à l’Observatoire à vraiment acheter et utiliser un clusteur parallèle. Il y avait eu des clusters des planétologues, mais qui était remplis de travaux séquentiels, où sur lequel seul Jean-Marc Petit avait fait des tests de code parallèle avec une bibliothèque ancêtre de MPI (Message Passing Interface). Nous étions donc vraiment les premiers à utiliser intensivement nos codes parallèles pour mener nos travaux de recherche. Plusieurs années aupa-ravant, il y avait eu des programmes codés pour la connexion machine de Sophia Antipolis par Hans Scholl. Eqbert Zienichie post-doc d’Hèlene Politano et Annick Pouquet avait programmé un code spectral avec une bibliothèque propre à la ma-chine parallèle T3E de l’IDRIS. Mais ces programmes étaient trop dépendants de bibliothèque ou d’architecture spécifiques et obsolètes.

Le cluster «Madness» semble maintenant «pathétique» et désuet (Fig. A.11), mais il y a 10 ans, il nous a permis de nous confronter avec les premiers calculs parallèle et d’acquérir l’expérience nécessaire pour calculer maintenant sur les plus grands clusters actuels. Les problèmes d’équilibre entre le temps de calcul et le temps de communication ont été mis en évidence avec les 2 versions successives du réseaux d’interconnexion que nous avions achetés. Par la suite l’Observatoire a acquis des ordinateurs parallèles plus puissants (SIVAM I et SIVAM II), qui ont suivit d’expérience et de base de lancement à l’acquisition du mésocentre actuel de 1800 coeurs ( http ://crimson.oca.eu ).

A.5. Parallélisation 57

Figure A.11 – Cluster MADNESS (Machine Actively Devoted to Numerical Experiments and Sophisticated Simulations) comportant 8 PC bi-processeurs AMD Athlon (1.8 GHz/proc) reliés par un réseau Gbytes, achetés en 2002. Ce cluster nous a permis de plonger dans l’univers du calcul parallèle.

58 Annexe A. Méthodes numériques et diagnostics

A.5.1 Penser Parallèle

Le domaine de calcul est généralement découpé en parties égales. Les clefs pour comprendre comment construire un code parallèle, sont de réaliser que le cube est découpé et distribué sur chaque processeur, et que le domaine entier n’existe plus comme dans un programme séquentiel. Il faut aussi réaliser que chaque processeur lit le même code, donc chaque fonction ou sous-programme doit être penser pour tous les processeurs en même temps. Nous ne sommes pas dans une configuration de communication Maître-Esclave, mais plutôt dans une approche plus démocra-tique, ou les processeurs sont égaux, font généralement la même chose, et parfois des actions spécifiques selon le morceau du domaine sur lequel ils doivent travailler. Avec la bibliothèque MPI (Message Passing interface), chaque processeur connaît son propre numéro et le nombre total de processeurs utilisés. Avec cette bibliothèque, qui comporte une interface pour une communication de processeur à processeur (local) et aussi des communication globales, il devient facile de faire parler les différentes parties du domaine, de rassembler ou de distribuer des données. Cette bibliothèque s’est un peu enrichie avec le deuxième version notamment la prise en compte de la lecture ou de la sauvegarde sur fichiers.

A.5.2 Entrées-Sorties en Parallèle (MPI-IO)

C’est une partie que j’ai implanté plus tard vers 2004. En effet, chaque processeur écrivait ou lisait dans un fichier qui lui était propre et, à la fin de la simulation des scripts rassemblaient les données. Mais lorsque l’on commence à utiliser au delà de 512 processeurs, le nombre de fichiers devient trop grand. J’ai eu des problèmes avec la limite inode sur certain cluster. Il devenait nécessaire d’introduire les nouvelles fonctionnalité de la bibliothèque de MPI version 2, l’écriture ou la lecture sur un seul fichier par tous les processeurs en même temps. Je me rappelle avoir fait une grande partie du travail dans un avion Londres-Denver, car j’allais travailler avec Annick Pouquet à Boulder. Ces fonctionnalités peuvent être plus ou moins optimisées par le constructeur et la version de la bibliothèque MPI utilisée. Elles sont maintenant incontournables.

Figure A.12 – A gauche, représentation de la fonction MPI_All_read, où chaque processeur va lire une partie du fichier et à droite l’équivalent MPI_All_write pour écrire dans un seul fichier des morceaux provenant de chaque processeurs.

A.5. Parallélisation 59

A.5.3 Découpage de la grille, FFT et optimisation

La grille est découpée et distribuée sur les différents processeurs. La première approche est de découper la grille en tranche (Fig. A.13). Dans cette configura-tion, la transformée de Fourier tri-dimensionnelle est locale dans chaque tranche pour deux directions d’espace et distribuée dans la troisième direction. Pour pou-voir appliquer la transformée de Fourier dans cette troisième direction, il faut faire une transposition du cube pour avoir toutes les données localement. Cette trans-position nécessite une communication globale gérée suivant différentes stratégies : Chaque tranche est coupé virtuellement en un nombre de bâtonnet (pencil) égales au nombres de processeurs (Fig.A.14) et chaque bâtonnet est échangé deux à deux entre deux processeurs. On peut remarquer que la diagonale n’a pas besoin de se déplacer. Une transposition local de chaque bâtonnet est ensuite appliquée.

Il y a deux manières de programmer cette transposition :

l’une utilise la communication point à point en échangeant deux bâtonnet deux à deux et en laissant la diagonale en place. Pour finir avec la transposition locale. Cette méthode est programmée «maison», on peut essayé d’optimiser en utilisant des communications point à point non bloquantes, ce qui permet de mélanger commu-nication et calcul. Notamment, lorsque l’on veut faire une transformée de Fourier sur un vecteur qui a trois composantes scalaires indépendantes, on peut alterner communication d’une composante avec calcul de FFT local sur l’autre. Il faut bien sur vérifier l’efficacité d’une telle approche.

L’autre approche est d’utiliser la fonction fournie par la bibliothèque MPI : MPI_All_to_all, qui s’occupe elle-même d’échanger les bâtonnets avec sa propre optimisation.

Il est bien d’avoir différentes stratégies, car il n’est pas du tout sûr que celle qui est la plus rapide sur une architecture, le soit sur tout autre cluster.

Figure A.13 – Décomposition de la grille de calcul en tranches égales, qui peuvent être ensuite gérées localement par multiples processeurs partageant la mémoire.

Nous envisageons aussi, une stratégie qui mélangerait des communications MPI noeud à noeud et qui utiliserait un partage de tâche sur chaque noeud avec les bibliothèques «OpenMP» ou «Multithread». La tranche de la grille serait donc encore découpée au niveau du noeud en fonction du nombre de coeurs par noeud et la transposition se ferait de noeud à noeud (Fig A.13). Cette stratégie est aussi

60 Annexe A. Méthodes numériques et diagnostics

Figure A.14 – Représentation bi-dimentionnel de l’algorithme de transposition, impliquant les bâtonnets.

en cours d’étude et d’implantation. Elle suggère une prise en charge plus globale des calculs sur ce découpage hybride (MPI-multithread). Cette stratégie peut être aussi envisagée pour des géométries non complètement périodiques ou des géométrie sphériques. En effet, dans la géométrie du plan (2 directions périodiques + une direction non périodique) ou celle de la sphère (2 directions gérées par les harmoniques sphériques (θ,φ) + une direction non périodique (celle du rayon) ), on retrouve un découpage en tranche qui pourrait être aussi distribué sur un noeud multi-coeurs et optimisé par des communications «MPI-multithread».

FigureA.15 – Découpage en bâtonnet (Pencil)

Une autre façon de découper qui est déjà largement utilisée pour le cube pério-dique est le découpage en bâtonnets (Fig.A.15). Il y a pas mal d’avantage à se tour-ner vers ce découpage : Avec un découpage en tranches, il y a une limite au nombre de processeur utilisables. Pour une simulation en N3, on ne peut avoir pas plus de N tranches et donc N processeurs. Par contre avec les bâtonnets on peut très facilement dépasser cette limite. Certes, il faut appliquer deux transpositions successives, ce qui implique en théorie plus de communications. Mais la communication se fait sur des données plus grosses que le cas limite des N tranches sur N processeurs, et subit moins les problèmes de la performance de la latence du cluster. Une bibliothèque freeware (P3DFFT) propose cette stratégie (http ://code.google.com/p/p3dfft/ ) et elle est utilisée avec succès par certains collègues qui voient leur code rester «scalable», sur plus de 10 000 processeurs pour une résolution de 10243 à 20483. Ce découpage et son introduction est notre prochaine priorité dans notre code «cubby».