Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Travaux pratiques MPI
• 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
• Exemples de programmes
• Communication
• Calcul de P
• 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 : http://www.open-mpi.org,...
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Schéma général d’un programme MPI
rang identificateur du processus en cours par rapport à un communicateur si (rang = identificateur_spécifique) alors
faire un traitement sinon
faire un autre traitement
p0
p1
p2
p3
p4
p5
p6
Communicateur A Communicateur B
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 hello.exe hello.c) Exécution:
$./a (ou /home/……./a.exe ou ./hello) Résultat:
$ Hello World!
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
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 machine.txt -n 4 hostname
Quelques fonctions MPI (1/2)
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)
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)
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)
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Quelques fonctions MPI (2/2)
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 ) Opérations :
MPI_MAX : maximum MPI_MIN : minimum
MPI_SUM : sum MPI_PROD : product
MPI_LAND : logical and MPI_BAND : bit-wise and MPI_LOR : logical or MPI_BOR : bit-wise or MPI_LXOR: logical xor MPI_BXOR : bit-wise xor
MPI_MAXLOC : max value + location MPI_MINLOC : min value + location Liste complète (≈360 fonctions) : https://www.open-mpi.org/doc/v1.8
Exemples de programmes
• Exemple 1 : Communication entre processus
• Exemple 2 : Calcul de P
• Exemple 3 : Gestion des groupes
• Exemple 4 : Gestion des communicateurs
• Exercices
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
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) p0
p2 p3
p1
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 */
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Programme de communication (2/3)
/* 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);
}
Programme de communication (3/3)
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;
}
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Exercice 1
a) Compilation
$mpicc -o helloMPI.exe helloMPI.c -lm b) Exécution
$mpirun -n 5 helloMPI.exe 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 sum0
pour i = rank + 1 à num_intervals pas num_procs x=h * (i – 0,5)
sum = sum + 4*racine_carrée(1 – x
2) mypi = h* sum
reduce(mypi,pi)
si (rank = 0) alors écrire(″PI=″, pi)
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Schéma du calcul de P
Hypoyhèse :
num_procs = 3 (p0, p1 et p2) num_intervals =10 donc h = 0,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
p0 p1 p2 p0 p1 p2 p0 p1 p2 p0 1 1Programme 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;
}
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Programme du calcul de P (2/5)
/* 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);
} }
Programme du calcul de P (3/5)
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);
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Programme du calcul de P (4/5)
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);
}
Programme du calcul de P (5/5)
/* 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;
}
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Exercice 2
a) Compilation
$mpicc -o helloMPI.exe helloMPI.c b) Exécution
$mpirun -n 4 helloMPI.exe
c) Corriger le programme pour calculer P
d) Créer calculMod.c tel que P = 4 *
∫
dx/(1 + x2)e) Quelle est la version qui donne les meilleures précisions relativement à num_intervals réduit sachant que les 25 chiffres de P sont :
Pi25 = 3,141592653589793238462643
f) Déterminer le temps d’exécution des deux versions en utilisant MPI_Wtime()
0 1
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Algorithme de gestion des groupes
NBPROCS=8
rank1={0,1,2,3}, rank2=[4,5,6,7}
rank identificateur du processus p nombre total des processus
si (rank < NBPROCS / 2) alors inclure(rank,groupe1)
Sinon
inclure (rank,groupe2) recevoir(message,source) écrire(message)
22
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Programme de gestion des groupes (1/2)
#include "mpi.h"
#include <stdio.h>
#define NPROCS 8
int main(argc,argv) int argc; char *argv[]; {
int rank, new_rank, sendbuf, recvbuf, ranks1[4]={0,1,2,3},ranks2[4]={4,5,6,7};
MPI_Group orig_group, new_group;
MPI_Comm new_comm;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
sendbuf = rank;
/* Extract the original group handle */
MPI_Comm_group(MPI_COMM_WORLD, &orig_group);
Programme de gestion des groupes (2/2)
/* Divide tasks into two distinct groups based upon rank */
if (rank < NPROCS/2)
MPI_Group_incl(orig_group, NPROCS/2, ranks1, &new_group);
else
MPI_Group_incl(orig_group, NPROCS/2, ranks2, &new_group);
/* Create new communicator and then perform collective communications */
MPI_Comm_create(MPI_COMM_WORLD, new_group, &new_comm);
MPI_Allreduce(&sendbuf, &recvbuf, 1, MPI_INT, MPI_SUM, new_comm);
MPI_Group_rank (new_group, &new_rank);
printf("rank= %d newrank= %d recvbuf= %d\n",rank,new_rank,recvbuf);
MPI_Finalize();
}
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Algorithme de gestion des communicateurs
mon_rang identificateur du processus P nombre total des processus
si (mon_rang < NBPROCS 0) alors inclure(mon_rang,groupe1)
Sinon
inclure (mon_rang,groupe2) recevoir(message,source)
écrire(message)
Programme de gestion des communicateurs
#include <stdio.h>
#include <mpi.h>
main(int argc, char **argv) {
MPI_Comm row_comm, col_comm;
int myrank, size, P=4, Q=3, p, q;
MPI_Init (&argc, &argv);
MPI_Comm_rank (MPI_COMM_WORLD, &myrank);
MPI_Comm_size (MPI_COMM_WORLD, &size); /* Determine row and column position */
p = myrank / Q; q = myrank % Q; /* pick a row-major mapping */ /* Split comm into row and column comms */
MPI_Comm_split(MPI_COMM_WORLD, p, q, &row_comm); /* color by row, rank by column */ MPI_Comm_split(MPI_COMM_WORLD, q, p,
&col_comm); /* color by column, rank by row */
printf("[%d]:My coordinates are (%d,%d)\n",myrank,p,q);
MPI_Finalize();
Architectures parallèles, M. Eleuldj, Département Génie Informatique, EMI, octobre 2014
Exercice 3
a)
Compilation$mpicc -o groupe.exe groupe.c b) Exécution
$mpirun groupe.exe
c) Diviser MPI_COMM_WORLD en 3 communicateurs non chevauchés (non- overlapped) tels que :
processus du rang 0, 3, 6,... appartient au premier groupe processus du rang 1, 4, 7,... appartient au deuxième groupe processus du rang 2, 5, 8,... appartient au troisième groupe