MPI : comment ça marche ?

En fait, le MPI (pour Message Passing Interface) est une librairie de fonctions et macros installée sur un système d’exploitation (linux) qui permet l’utilisation de plusieurs processeurs en parallèle. Le but de cet article n’est pas de donner un historique ni un enseignement détaillé de la méthode. Pour cela, on peut trouver beaucoup d’ouvrages et de documents en libre téléchargement sur internet. Le but étant plutôt de donner rapidement et le plus simplement possible une introduction ou plutôt une idée : comment ça marche. Juste pour vous dire que c’est simple et que vous pouvez facilement adopter la démarche.

Un programme monoprocesseur est une suite d’instructions séquentielles exécutées par un seul ordinateur. L’équivalent du même programme en parallèle sera une autre version de celui-ci distribuée à un certain nombre de processeur (cluster) où chacun doit se reconnaitre et n’exécuter que les tâches qui lui sont affectées. C’est un peu comme un monologue et une pièce théâtrale normale.

Pour exécuter un programme en parallèle, il faut donc réécrire le programme en distribuant les taches aux différents processeurs impliqués dans le calcul. J’insiste sur le fait que c’est la même version du code qui est distribuée en même temps à tous les processeurs. Ensuite, chaque processeur s’identifie et exécute les taches qu’ils lui sont affectées. Bien sûr il y a un ordre séquentiel à respecter et chaque processeur doit savoir exactement quand exécuter sa tâche par rapport aux autres processeurs. Des fois il est utile de définir un processeur comme maître (master). C’est lui le patron qui synchronise les taches et les autres ne sont que des esclaves (slaves) exécutants des taches précises.

Pour bien illustrer tout ce blabla, rien de mieux qu’un exemple concret et pratique. Pour cela nous allons utiliser l’exemple du calcul d’intégrale par la méthode des trapèzes. (L’exemple est inspiré de l’ouvrage de Pacheco et Ming, MPI User Guide in Fortran)

Rappelons que la méthode des trapèzes consiste à estimer l’intégrale d’une fonction f(x) sur un intervalle [a,b] par la division de cet intervalle en n segments égaux et calculer la somme suivante :

h[f(x0)/2 + f(xn)/2 + somme(de i=1 à i=n-1) (f(xi))]

où, h=(b-a)/n, et xi=a+ih, i=0,.. .,n

Le programme monoprocesseur qui correspond à cet algorithme est donné ici.

Vous pouvez le compiler en exécutant l’instruction suivante : ifort trapezoidal-mono.f (ifort pour Intel Fortran)

Et l’exécuter en tapant : ./a.out  (a.out est le fichier exécutable généré par défaut)

Passons maintenant à la version parallèle du code : l’idée est de diviser l’intervalle [a,b] en autant de sous-intervalle qu’il y a de processeur. Chaque processeur calcule l’intégrale dans son sous-intervalle et à la fin il faut faire la somme des résultats pour trouver la valeur finale.

Supposons qu’on dispose de p processeurs et de n trapèzes et pour simplifier disons que le n est divisible par p. donc, on va dire que le premier processeur exécute l’intégrale sur la surface des premiers n/p trapèzes. Le deuxième processeur exécute l’intégrale sur la surface des n/p trapèzes suivants et ainsi de suite.

Donc le processeur de rang q va calculer l’intégrale sur l’intervalle suivant :

[a+q(nh/p) , a+(q+1)(nh/p)]

D’où chaque, processeur doit avoir les infos suivantes :

  • Le nombre de processeur impliqués dans le calcul, p.
  • Son rang à lui, q, c’est-à-dire sa position parmi les autres processeurs.
  • L’intervalle de l’intégration [a,b].
  • Le nombre de sous-intervalles décidé, n.

Pour notre exemple, nous allons décider de la stratégie suivante :

Chaque processeur envoie son sous-calcul au processeur de rang 0 et celui-ci doit faire la somme de toutes les valeurs reçues et restituer le résultat final. On va aussi décider que le processeur de rang 0 aura à faire un sous-calcul comme les autres. Ceci étant pour enlever toute ambiguïté sur la notion maître-esclave évoquée un peu plus haut et affirmer que la responsabilité est plutôt un devoir que des privilèges. Bien sûr, ceci n’a rien à voir avec le MPI c’est juste d’ordre psychologique.

La version parallèle du même programme précèdent est donnée ici :  trapezoidal-mpi.f

Les commentaires :

.

Include ‘mpif.h’

.

Call MPI_Init(ierr)

.

Call MPI_Finialize(ierr)

.

End program

  • Le fichier mpif.h contient les fonctions et les macros nécessaires pour l’exécution du code en parallèle. Cette déclaration est indispensable au début de chaque programme MPI.
  • La première instruction MPI à appeler est MPI_init(ierr). Cette fonction est appelée une fois et toujours en premier. L’argument ierr renvoi un code d’erreur en cas de problème.
  • A la fin d’un programme MPI, on appelle la fonction MPI_Finalize. Cette fonction nettoie le processus et termine toute les fonctions MPI appelées.

Les instructions:

MPI_comm_rank (comm, rank,terror) : cette instruction retourne le rang (rank) du processeur.

MPI_comm_size (comm, P, ierror) : cette instruction donne le nombre (p) de processeur impliqués dans le calcul

MPI_send et call MPI_recv: deux instructions pour envoyer et recevoir des messages. Dans les arguments de ces deux instructions on doit reconnaitre le rang de l’envoyeur, le rang du récepteur, et le message envoyé.

Le reste c’est simple à suivre. Il y a des tests (if) un peu partout pour déterminer qui fait quoi. Pour faire court, je ne vais pas détailler les arguments de chaque instruction. On pourra y revenir si nécessaire.

Sinon en pratique ça se passe comme suit:

  • Pour compiler le programme il faut utiliser l’instruction suivante : mpif90 program.f. Le compilateur retourne le fichier exécutable nommé a.out
  • Pour l’exécuter il faut taper : mpirun –np 4 ./a.out

Ici j’ai choisi d’utiliser 4 processeurs (à changer suivant le besoin).

Bien sûr pour faire du MPI il y a plusieurs approches et ça change suivant la nature de l’application. Pour nous utilisateurs de la CFD, l’approche consiste à suivre la même démarche de l’exemple ci-dessus: diviser le domaine de calcul en sous-domaines, affecter chaque sous-domaine à un processeur et assurer la communication entre eux à travers les frontières virtuelles séparant les sous-domaines.

J’ai essayé de faire le plus court possible et je pourrai y revenir sur certains points si nécessaire.

Ce contenu a été publié dans Articles. Vous pouvez le mettre en favoris avec ce permalien.

2 réponses à MPI : comment ça marche ?

  1. walid dit :

    Aujourd’hui l’ordinateur est un outil incontournable et pour cette raison qu’on voit aujourd’hui le top de la technologie en oubliant pas influence de cette technologie surtout dans le domaine scientifique. Si on voit ce qu’a fait le Nvidia surtout dans le calcul parallèle et que n’était pas faisable il y a des années par exemple l’écoulement du sang dans le cœur en temps réel et c’était impossible auparavant c’est grâce à MPI et CUDA OPENMP que le calcul parallèle se développes d’une manière rapide ..

  2. Bon article de vulgarisation de MPI !

Les commentaires sont fermés.