Chapitre 3 MPI2

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 12

Calcul Parallèle. Chapitre 3.

Message Passing Interface MPI 1/12

3.1. Structure d’un programme MPI

Utilisation de la bibliothèque MPI :


...
#include "mpi.h"

int my_rank; /* Rang du processus */


int p; /* Nombre de processus */
...
main (int argc, char *argv []) {
...
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &p);
...
MPI_Finalize () ;
...
}

Les mesures de temps peuvent se faire de la façon suivante :

MPI est une bibliothèque contenant plus de 120 fonctions, mais seules quelques-unes (moins
d’une dizaine) sont nécessaires pour un programme simple.

 Pour utiliser MPI, un programme doit inclure le header de MPI : #include "mpi.h"
 Ensuite, MPI_Init(argc, argv) doit être appelé avant toute autre fonction de la
bibliothèque MPI, et MPI_Finalize(void) doit être appelé à la fin de l’exécution du logiciel
pour libérer les ressources.
 Les communications dans un programme MPI sont organisées par groupes de
communication. Cette fonctionnalité peut s’avérer très utile pour des programmes un peu
complexes, mais, dans notre cas, nous nous contenterons du groupe de communication
MPI_COMM_WORLD qui contient tous les nœuds.

 On peut obtenir la taille du groupe de communication (avec MPI_COMM_WORLD) en


appelant la fonction int MPI_Comm_size(MPI_Comm, int *size), par exemple :
MPI_Comm_size(MPI_COMM_WORLD, &size);
 Chaque nœud MPI a un rang dans son groupe de communication, et il s’obtient en
appelant la fonction int MPI_Comm_rank(MPI_Comm comm, int *rank) comme dans :
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
 Pour envoyer un message de façon bloquante, on utilise int MPI_Send(void* buf, int
count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm): buf contient les
données à envoyer, rank est le rang du nœud (comme obtenu par MPI_Comm_rank()) à
qui on envoie la donnée et tag permet de savoir à quoi correspond cette donnée. Par
exemple :
#define TAG TAG_NB_TRAPEZES 1000

.
Calcul Parallèle. Chapitre 3. Message Passing Interface MPI 2/12

int nb_trapezes = 100000;


MPI_Send(&nb_trapezes, 1, MPI_INT, 0, TAG_NB_TRAPEZES,
MPI_COMM_WORD);
 La fonction réciproque, pour recevoir un message de façon bloquante, est int
MPI_Recv(void* buf, int count, MPI_Datatype datatype, int source, int tag,
MPI_Comm comm, MPI_Status *status); comme dans :
int nb_trapezes;
MPI_Status status;
MPI_Recv(&nb_trapezes, 1, MPI_INT, MPI_ANY_SOURCE, TAG_NB_TRAPEZES,
MPI_COMM_WORLD, &status);
status contenant des informations sur le message reçu :

status.count = message length


status.MPI_SOURCE = message sender
status.MPI_TAG = message tag

A noter qu‘on peut aussi utiliser MPI_ANY_TAG pour accepter des messages quel que soit
leur tag. Il est de plus possible d’envoyer une donnée à tous les nœuds, en utilisant int
MPI_Bcast(void* buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm) :
selon que le nœud en question envoie (son rang est alors égal à la valeur de root) ou reçoit,
buffer contient la valeur à envoyer ou est l’endroit où sera écrite la valeur ; Par exemple :

long long int num_trap = 100000;


MPI_Bcast((void *) &num_trap, 1, MPI_LONG_LONG_INT, 0,
MPI_COMM_WORLD);

Pour récupérer sur un nœud une valeur de chacun des nœuds, il convient d’utiliser int
MPI_Gather(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int
recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm). Les noms des arguments
sont assez explicites. Voici un exemple d’utilisation :

int size;
int rank;
double *sum_buf = NULL;
double sum = 0;
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if ( rank == 0 )
sum_buf = malloc(sizeof(double)
* size);
MPI_Gather((void *)&sum, 1,
MPI_DOUBLE, sum_buf, 1,
MPI_DOUBLE, 0,
MPI_COMM_WORLD);

3.2. Hello world Un premier programme MPI

 p processus : P0 à Pp�1

.
Calcul Parallèle. Chapitre 3. Message Passing Interface MPI 3/12

 Les processus Pi;i>0 envoient un message (chaîne de caractères) à P0


 P0 recoit p - 1 messages et les affiche

 Programmation SPMD (Single Program Multiple Data)

Hello World (code C, initialisation)

#include <stdio.h>
#include "mpi.h"
main(int argc, char *argv[]) {
int my_rank; /* Rang du processus */
int p; /* Nombre de processus */
int source; /* Rang de l’emetteur */
int dest; /* Rang du recepteur */
int tag = 50; /* Tag des messages */
char message[100]; /* Allocation du message */
MPI_Status status; /* Valeur de retour pour le recepteur */
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &p);

Hello World (code C, corps)


if (my_rank != 0) {
/* Creation du message */
sprintf(message, "Hello from process %d!", my_rank);
dest = 0;
/* strlen + 1 => le ’\0’ final est envoye */
MPI_Send(message, strlen(message)+1, MPI_CHAR, dest,
tag, MPI_COMM_WORLD);
} else { /* my_rank == 0 */
for (source = 1; source < p; source++) {
MPI_Recv(message, 100, MPI_CHAR, source, tag,
MPI_COMM_WORLD, &status);
printf("%s\n", message);
}
}
MPI_Finalize();
} /* main */

.
Calcul Parallèle. Chapitre 3. Message Passing Interface MPI 4/12

 Principaux types de données de base (C)

3.3. Communications point à point

 Une communication dite point à point a lieu entre deux processus, l’un appelé processus
émetteur et l’autre processus récepteur (ou destinataire).

L’émetteur et le récepteur sont identifiés par leur rang dans le communicateur.


 Ce que l’on appelle l’enveloppe d’un message est constituée :
o du rang du processus émetteur ;
o du rang du processus récepteur ;
o de l’étiquette (tag) du message ;
o du nom du communicateur qui définira le contexte de communication de
l’opération.
 Les données échangées sont typées (entiers, réels, etc. ou types dérivés personnels).

Exemple :

.
Calcul Parallèle. Chapitre 3. Message Passing Interface MPI 5/12

 Communication sendrecv entre les processus 0 et 1

.
Calcul Parallèle. Chapitre 3. Message Passing Interface MPI 6/12

MPI Sendrecv() utilise un ordre MPI Send() suivi d’un ordre MPI Recv(). En effet,
chacun des deux processus attendrait un ordre de réception qui ne viendrait jamais,
puisque les deux envois resteraient en suspens.

Eviter Sendrecv()  MPI_Send et MPI_Recv

Exemple : anneau de communication


Pour que les communications se fassent réellement en anneau, à l’image d’un passage
de jeton entre processus, il faut procéder différemment et faire en sorte qu’un
processus initie la chaîne :

3.4. Communications collectives


Les communications collectives permettent de faire en une seule opération une série de
communications point à point. Une communication collective concerne toujours tous les
processus du communicateur indiqué.
.
Calcul Parallèle. Chapitre 3. Message Passing Interface MPI 7/12

– Synchronisation globale : MPI Barrier()

 Diffusion générale : MPI Bcast()

.
Calcul Parallèle. Chapitre 3. Message Passing Interface MPI 8/12

– Diffusion sélective : MPI Scatter()

.
Calcul Parallèle. Chapitre 3. Message Passing Interface MPI 9/12

– Collecte : MPI Gather()

.
Calcul Parallèle. Chapitre 3. Message Passing Interface MPI
10/12

– Collecte générale : MPI Allgather()

.
Calcul Parallèle. Chapitre 3. Message Passing Interface MPI
11/12

– Echanges croisés : MPI Alltoall()

.
Calcul Parallèle. Chapitre 3. Message Passing Interface MPI
12/12

Vous aimerez peut-être aussi