Travaux pratiques
MPI
PLAN
• Présentation de MPI
• Schéma général d’un programme MPI
• Exécution d’un programme C
• Quelques commandes Unix
• Quelques fonctions MPI
PLAN(suite)
• Exemples de programmes
–Communication
–Calcul de
–Gestion des groupes
–Gestion des communicateurs
• Projets de TP
Présentation de MPI (Message Passing
Interface)
• Bibliothèque standard à inclure dans un
programme C (#include "mpi.h") ou
Fortran (INCLUDE ’mpif.h’)
• Ancêtre : PVM (Parallel Virtual Machine)
en 1991
• Plusieurs implantations : MPI-1(1994),
MPICH2(2000) et OpenMPI(2009)
• Autres bibliothèques : OpenMP(2010),…
• Souvent utilisée dans des architectures à
mémoire distribuée
• Modèle SPMD (Single Programme Multiple
Data
– Le même programme est installé dans chaque
processeur (ou machine)
– Des instances multiples du programme traitent
partiellement ou totalement les données
– Chaque instance a un identificateur unique
par rapport à un communicateur
– L’instance exécute la partie du programme
selon son identificateur
• Référence : [Link]
Schéma général d’un programme
MPI
rangidentificateur du processus en cours
par rapport à un communicateur
si (rang = identificateur_spécifique) alors
faire un traitement
sinon
faire un autre traitement
Exécution d’un programme C
/* fichier hello.c*/
#include <stdio.h>
int main() {
printf("Hello World!");
return 0;
}
• Compilation:
$gcc hello.c (ou gcc –o [Link] hello.c)
• Exécution:
$./a (ou /home/……./[Link] ou ./hello)
• Résultat:
$ Hello World!
Quelques commandes Unix
• $pwd
• $ls -l
• $hostname
• $mpirun -n 1 hostname
• (ou mpiexec -np 1 hostname)
• $mpirun -n 7 hostname
• $mpirun hostname
• $mpirun -n 5 hello
• $mpirun -n 12 hello
• $mpirun -machinefile [Link] -n 4 hostname
Quelques fonctions MPI (1/6)
• int MPI_Init(int *argc, char ***argv)
• int MPI_Finalize()
• int MPI_Comm_rank(MPI_Comm comm, int *rank)
• int MPI_Comm_size(MPI_Comm comm, int *size)
• int MPI_Send(const void *buf, int count,
MPI_Datatype datatype, int dest, int tag, MPI_Comm
comm)
Quelques fonctions MPI (2/6)
• int MPI_Recv(void *buf, int count, MPI_Datatype
datatype, int source, int tag, MPI_Comm comm,
MPI_Status *status)
• int MPI_Bcast(void *buffer, int count, MPI_Datatype
datatype, int root, MPI_Comm comm)
Quelques fonctions MPI (3/6)
• int MPI_Comm_group(MPI_Comm comm,
MPI_Group *group)
• int MPI_Group_incl(MPI_Group group, int n,
const int ranks[], MPI_Group *newgroup)
• int MPI_Comm_create(MPI_Comm comm,
MPI_Group group, MPI_Comm *newcomm)
Quelques fonctions MPI (4/6)
• int MPI_Reduce(void *sendbuf, void
*recvbuf, int count, MPI_Datatype
datatype, MPI_Op op, int root,MPI_Comm
comm)
• Int MPI_Allreduce( void *sendbuf, void
*recvbuf, int count, MPI_Datatype
datatype, MPI_Op op, MPI_Comm comm )
Quelques fonctions MPI (5/6)
• Opérations :
• MPI_MAX : maximum
• MPI_SUM : sum
• MPI_LAND : logical and
• MPI_LOR : logical or
• MPI_LXOR: logical xor
• MPI_MAXLOC : max value + location
Quelques fonctions MPI (6/6)
• MPI_MIN : minimum
• MPI_PROD : product
• MPI_BAND : bit-wise and
• MPI_BOR : bit-wise or
• MPI_BXOR : bit-wise xor
• MPI_MINLOC : min value + location
Liste complète (≈360 fonctions) :
[Link]
Exemples de programmes
• Exemple 1 : Communication entre processus
• Exemple 2 : Calcul de
• Exemple 3 : Gestion des groupes
• Exemple 4 : Gestion des communicateurs
• Exercices
Algorithme de communication
Algorithme de communication
p nombre total des processus
rang identificateur du processus
si (rang ≠ 0) alors
message ″Hello world du processus″ + rang
envoyer(message,0)
sinon
écrire(″Hello world du processus 0:nombre
de processus ″,p)
pour source=1 à (p-1) faire
recevoir(message, source)
écrire(message)
Programme de communication (1/3)
/* programme helloMPI.c*/
#include <stdio.h>
#include <string.h>
#include "mpi.h“
int main(int argc, char* argv[]){
int my_rank; /* rank of process */
int p; /* number of processes */
int source; /* rank of sender */
int dest; /* rank of receiver */
int tag=0; /* tag for messages */
char message[100]; /* storage for message */
MPI_Status status ; /* return status for receive */
/* start up MPI */
MPI_Init(&argc, &argv);
/* find out process rank */
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
/* find out number of processes */
MPI_Comm_size(MPI_COMM_WORLD, &p);
if (my_rank !=0){
/* create message */
sprintf(message, "Hello MPI World from process %d!", my_rank);
dest = 0; /* use strlen+1 so that '\0' get transmitted */
MPI_Send(message, strlen(message)+1, MPI_CHAR,dest,
tag,MPI_COMM_WORLD);
}
else{
printf("Hello MPI World From process 0: Num processes: %d\n", p);
for (source = 1; source < p; source++) {
MPI_Recv(message, 100, MPI_CHAR, source, tag, MPI_COMM_WORLD,
&status);
printf("%s\n", message);
}
}
/* shut down MPI */
MPI_Finalize();
return 0;
}
Exercice 1
a) Compilation
$mpicc -o [Link] helloMPI.c -lm
b) Exécution
$mpirun -n 5 [Link]
c) Création de helloMPIMod.c
supprimer l’appel MPI_Send
exécuter le programme
Que se passe-t-il ?
d) Création de course.c
supprimer les appels MPI_Send
supprimer la boucle lorsque my-rank=0
(processus p0)
remplacer sprintf par printf (un affichage par
processus)
exécuter le programme à 2 reprises
Que se passe-t-il ?
Algorithme du calcul de P
Calc_pi(rank, num_procs)
si (rank = 0) alors
num_intervals 1000
diffuser(num_intervals)
h 1/num_intervals
sum 0
pour i = rank + 1 à num_intervals pas num_procs
x=h * (i – 0,5)
sum = sum + 4*racine_carrée(1 – x2)
mypi = h* sum
reduce(mypi,pi)
si (rank = 0) alors écrire(″PI=″, pi)
Schéma du calcul de P
Hypoyhèse :
num_procs = 3 (p0, p1 et p2)
num_intervals =10 donc h = 0,1
1
p0 calcule les valeurs
x=0,05, x=0,35, x=0,65 et x=0,95
p1 calcule les valeurs
x=0,15, x=0,45 et x=0,75
p2 calcule les valeurs
x=0,25, x=0,55 et x=0,85
Programme du calcul de P (1/5)
/* fichier calculPi.c */
#include <mpi.h>
#include <stdio.h>
#include <string.h>
void calc_pi(int rank, int num_procs){
int i;
int num_intervals;
double h;
double mypi;
double pi;
double sum;
double x;
/* set number of intervals to calculate */
if (rank == 0) {
num_intervals = 1000;
}
/* tell other tasks how many intervals */
MPI_Bcast(&num_intervals, 1, MPI_INT, 0, MPI_COMM_WORLD);
/* now everyone does their calculation */
h = 1.0 / (double) num_intervals;
sum = 0.0;
for (i = rank + 1; i <= num_intervals; i += num_procs) {
x = h * ((double)i - 0.5);
sum += (4.0 * sqrt(1.0 - x*x));
}
mypi = h * sum;
/* combine everyone's calculations */
MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0,MPI_COMM_WORLD);
if (rank == 0) {
printf("PI is approximately %.16f\n", pi);
}
}
int main(int argc, char *argv[]) {
int my_rank; /* rank of process */
int num_procs; /* number of processes */
int source; /* rank of sender */
int dest = 0; /* rank of receiver */
int tag = 0; /* tag for messages */
char message[100]; /* storage for message */
MPI_Status status ; /* return status for receive */
/* start up MPI */
MPI_Init(&argc, &argv);
/* find out process rank */
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
/* find out number of processes */
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
if (my_rank != 0) {
/* create message */
snprintf(message,26, "Greetings from process %d!",
my_rank);
/* use strlen+1 so that '\0' get transmitted */
MPI_Send(message, strlen(message)+1, MPI_CHAR,
dest, tag, MPI_COMM_WORLD);
}
else {
printf("Num processes: %d\n",num_procs);
for (source = 1; source < num_procs; source++)
{
MPI_Recv(message, 100, MPI_CHAR,
source, tag, MPI_COMM_WORLD, &status);
printf("Process 0 received \"%s\"\n",message);
}
/* now return the compliment */
snprintf(message, 26, "Hi, how are you? ");
}
MPI_Bcast(message, strlen(message)+1, MPI_CHAR, dest,
MPI_COMM_WORLD);
if (my_rank != 0) {
printf("Process %d received \"%s\"\n", my_rank,
message);
}
/* calculate PI */
calc_pi(my_rank, num_procs);
/* shut down MPI */
MPI_Finalize();
return 0;
}
Exercice 2
a) Compilation
$mpicc -o [Link] helloMPI.c
b) Exécution
$mpirun -n 4 [Link]
c) Corriger le programme pour calculer P
•