Le broadcast (TP1)
Le broadcast est une opération collective qui consiste à répartir sur tous les processus une donnée se trouvant sur un processus source. La primitive MPI permettant d'effectuer cette opération est MPI_Bcast.
Dans ce TP, vous aurez en plus besoin de savoir comment synchroniser des processus et comment mesurer un temps écoulé dans un programme MPI, une bonne explication de ces différents points se trouve à cette adresse.
MPI Broadcast
Exemple d'utilisation de MPI broadcast :
#include <mpi.h>
#include <iostream>
#include <vector>
int main(int argc, char **argv) {
int myRank, nProc;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
MPI_Comm_size(MPI_COMM_WORLD, &nProc);
std::vector<int> vector(100, 0);
if(myRank == 0) vector = std::vector<int>(100, 1);
MPI_Bcast( vector.data(), vector.size(), MPI_INT, 0, MPI_COMM_WORLD );
std::cout << "myRank : " << myRank << ", value in the vector : " << vector.at(0) << std::endl;
MPI_Finalize();
}
Mesures de performances
Effectuez vos mesures de performances sur la machine baobab avec un broadcast d'un tableau de 100'000'000 de int avec 1, 2, 4, 8, 16, 32 et 64 coeurs.
Pour calculer un temps d'exécution, vous devez d'abord vous assurer que tout les processus atteignent le même point avant de commencer puis que tout les processus aient terminé l'opération. Pour ce faire, vous devez utiliser les primitives MPI_Barrier et MPI_Wtime.
Par exemple:
#include <mpi.h>
#include <iostream>
int main(int argc, char **argv) {
int myRank, nProc;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
MPI_Comm_size(MPI_COMM_WORLD, &nProc);
MPI_Barrier(MPI_COMM_WORLD);
double start = MPI_Wtime();
// execution de l'algorithme
MPI_Barrier(MPI_COMM_WORLD);
double end = MPI_Wtime();
if(myRank==0) std::cout << "temps de l'operation : " << end-start << "[s]" << std::endl;
MPI_Finalize();
}
Broadcast simple
pseudo code du broadcast simple (tout les pseudo codes sur cette page supposent que la source est le processus 0):
si rang = 0
pour i de 1 à nproc-1
envoyer data à i
sinon
recevoir data
Broadcast en anneau
pseudo code du broadcast en anneau:
si rang = 0
envoyer data à 1 et à 2 si ils existent
sinon
recevoir data
envoyer data à rang+2 si il existe
Broadcast sur un hypercube
pseudo code du broadcast sur un hypercube:
dimension est log2(nproc)
pour étape de 0 à dimension-1
si source à cette étape
voisin est le processus voisin dans la dimension étape+1
envoyer data à voisin
si récepteur à cette étape
recevoir data
La difficulté du broadcast sur un hypercube réside dans le fait qu'il faut être capable de déterminer si un processus est une source ou un récepteur à l'étape courante et quel est son voisin si le processus est une source.
Pour cela, il faut considérer que les processus sont disposés et adressés comme sur la figure 3.12 page 72 du cours, c'est à dire que les voisins d'un processus dans un hypercube sont les processus dont la valeur du rang ne diffère que d'un bit. Ensuite, on applique l'algorithme décrit sur la figure 3.14 page 74 du cours.
Pour savoir si un processus est une source à l'étape i, il faut regarder si il y a des 1 en position i ou plus de son adresse. Si ce n'est pas le cas, le processus est une source à cette étape. Pour savoir si un processus est un récepteur à l'étape i, il faut regarder si le bit i de son adresse vaut 1 et si il n'y a que des 0 sur la gauche. Si c'est le cas, le processus est un récepteur à cette étape.
Ensuite, pour calculer le voisin auquel envoyer le message si le processus est une source, il suffit d'inverser le bit se trouvant en position i de l'adresse du processus.
Par exemple si step va de 0 à dimension-1, test pour savoir si le processus est une source:
if(rank >> step == 0)
Test pour savoir si le processus est une destination:
if(rank >> step == 1)
Explication sur les shifts à gauche et à droite et sur les opérations logiques bit à bit en C/C++.