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 1
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,... 2
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 p2 p4 p5 p1 p3 p6 Communicateur A Communicateur B 3
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! 4
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 5
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) 6
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 7
Exemples de programmes Exemple 1 : Communication entre processus Exemple 2 : Calcul de P Exemple 3 : Gestion des groupes Exemple 4 : Gestion des communicateurs Exercices 8
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) p0 écrire(message) p1 p2 p3 9
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 */ 10
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); 11
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; 12
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? 13
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 x 2 ) mypi = h* sum reduce(mypi,pi) si (rank = 0) alors écrire( PI=, pi) 14
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 p0 p1 p2 p0 p1 p2 p0 p1 p2 p0 1 15
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; 16
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); 17
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); 18
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); 19
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; 20
Exercice 2 a) Compilation b) Exécution $mpicc -o hellompi.exe hellompi.c $mpirun -n 4 hellompi.exe c) Corriger le programme pour calculer P d) Créer calculmod.c tel que P = 4 * dx/(1 + x 2 ) 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() 1 0 21
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) P 22
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); 23
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(); 24
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) 25
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(); 26
Exercice 3 a) Compilation b) Exécution $mpicc -o groupe.exe groupe.c $mpirun groupe.exe c) Diviser MPI_COMM_WORLD en 3 communicateurs non chevauchés (nonoverlapped) 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 27
Références Ivan Lavallée, «Algorithmique parallèle et distribuée» Traité des nouvelles technologies, Hermes, 1990. Kai Hwang, «Advanced computer architecture: Parallelism, Sqcalability, Programmability», McGraw Hill Series in Computer Science, 1993. http://www.unix.mcs.anl.gov/mpi/tutorial/perf/index.ht ml http://www.unix.mcs.anl.gov/mpi «MPI : A message Passing Interface Standard», Message Passing Interface Forum, 1995 28