calcul parallèle et distribué - jullian/downloads/cpd.pdf · mémoire distribuée remarques. di...
Post on 15-Oct-2020
4 Views
Preview:
TRANSCRIPT
Calcul distribué
Calcul parallèle et distribué
Yann Jullian
Université François Rabelais
yann.jullian@univ-tours.frhttp://www.lmpt.univ-tours.fr/~jullian/
5 mars 2018
Calcul distribué
1 IntroductionMémoire partagéeMémoire distribuéeExemples de clustersMessage Passing InterfaceExemples de domaines d'applicationsQuelques liens
2 EnvironnementPremier exempleCompilation, exécutionComparaison avec OpenMPCommunicateur par défaut
3 Communications point à pointPrincipeExemplePrécisions sur le tagTypes de données de base
Calcul distribué
Remarques
4 Communications collectivesNotions généralesSynchronisation globale : MPI_BarrierDi�usion générale : MPI_BcastDi�usion sélective : MPI_ScatterCollecte : MPI_GatherCollecte générale : MPI_AllgatherDi�usion : MPI_ScattervCollecte : MPI_GathervCollectes et di�usions sélectives : MPI_Alltoall
5 Distribution équitableExtension du tableau et MPI_Scatter
Distribution sous-optimale avec MPI_Scatterv
Distribution optimale avec MPI_Scatterv
6 Communications collectives : réductionsRéductions réparties : MPI_Reduce
Calcul distribué
Réductions réparties : MPI_Reduce, MPI_SUM
Réductions réparties : MPI_Reduce, MPI_MAXLOC
Réductions réparties : MPI_Allreduce
7 Modes de communicationsFonctionsCommunications bloquantesEnvoi bloquant, mode bu�eriséEnvoi bloquant, mode synchroneEnvoi bloquant, mode readyEnvoi bloquant, mode standardCommunications non bloquantes
8 DeadlocksDé�nitionExemple
9 Types de données dérivésIntroductionExtraction contiguë : MPI_Type_contiguous
Calcul distribué
Extraction à pas constant : MPI_Type_vectorExtraction à pas variable : MPI_Type_indexedPaddingStructure de données MPI_Type_create_struct
10 CommunicateursPartitionner un communicateur
11 Analyse de codes MPIDebugMéthodologie de debug de code MPIPro�lage
Mesures temporelles simples
MPIP
MPE
OPro�le
Autres problèmesOpérations �otantes
Race condition
Calcul distribué
Introduction
1 IntroductionMémoire partagéeMémoire distribuéeExemples de clustersMessage Passing InterfaceExemples de domaines d'applicationsQuelques liens
Calcul distribué
Introduction
Mémoire partagée
1 IntroductionMémoire partagéeMémoire distribuéeExemples de clustersMessage Passing InterfaceExemples de domaines d'applicationsQuelques liens
Calcul distribué
Introduction
Mémoire partagée
Une unique machine.
Tous les c÷urs de tous les processeurs ont accès à la mémoire.
C0 C1
C2 C3
C0 C1
C2 C3
C0 C1
C2 C3
C0 C1
C2 C3
Noeud 0
Mem
oire
Avantage
Parallélisation simple (OpenMP par exemple).
Inconvénient
Nombre de processeurs et mémoire limités au départ. Pas d'extensionpossible au delà de la capacité de la machine sur laquelle on exécute.
Calcul distribué
Introduction
Mémoire distribuée
1 IntroductionMémoire partagéeMémoire distribuéeExemples de clustersMessage Passing InterfaceExemples de domaines d'applicationsQuelques liens
Calcul distribué
Introduction
Mémoire distribuée
Plusieurs machines connectées en réseaux.
Les processeurs d'un n÷ud n'ont pas accès aux mémoires des autresn÷uds.
C0 C1
C2 C3
C0 C1
C2 C3
C0 C1
C2 C3
C0 C1
C2 C3
C0 C1
C2 C3
C0 C1
C2 C3
C0 C1
C2 C3
C0 C1
C2 C3
Noeud 0 Noeud 1
Mem
oire
Mem
oire
Reseau
Avantage
On peut étendre le système en ajoutant des n÷uds.
Calcul distribué
Introduction
Mémoire distribuée
Inconvénients
Nécessité de transférer la mémoire d'un n÷ud à l'autre.
Le coût de communication réseau peut être élevé si le volume dedonnées à communiquer est important.
Le coût d'un transfert réseau sera toujours beaucoup plus importantqu'une simple copie mémoire.
Calcul distribué
Introduction
Mémoire distribuée
Remarques.
Di�érents threads d'un même processus ont accès à la mêmemémoire.
Di�érents processus n'ont jamais accès à la même mémoire, même siles processus sont lancés sur la même machine.
On peut donc aussi faire du calcul distribué avec une unique machine.
Calcul distribué
Introduction
Exemples de clusters
1 IntroductionMémoire partagéeMémoire distribuéeExemples de clustersMessage Passing InterfaceExemples de domaines d'applicationsQuelques liens
Calcul distribué
Introduction
Exemples de clusters
Ada
332 n÷uds de calculs
4 processeurs Intel E5− 4650 (8 c÷urs) à 2.7 GHz par n÷ud
10624 c÷urs
46 To de RAM
233 T�ops théoriques, 192 T�ops (linpack)
Puissance : 244 kWatt
E�cacité énergétique : 786 M�ops / watt
http://www.idris.fr/ada/ada-presentation.html
Calcul distribué
Introduction
Exemples de clusters
Turing
6144 n÷uds de calculs
16 processeurs POWER A2 (1 c÷ur) à 1.6 GHz par n÷ud
98304 c÷urs
96 To de RAM
1258 T�ops théoriques, 1073 T�ops (linpack)
Puissance : 493 kWatt
E�cacité énergétique : 2176 M�ops / watt
http://www.idris.fr/turing/turing-presentation.html
Calcul distribué
Introduction
Message Passing Interface
1 IntroductionMémoire partagéeMémoire distribuéeExemples de clustersMessage Passing InterfaceExemples de domaines d'applicationsQuelques liens
Calcul distribué
Introduction
Message Passing Interface
Message Passing Interface (MPI)
C'est un ensemble de règles dé�nissant les communications entreprocessus, possiblement de n÷uds di�érents.
C'est l'outil standard pour les communications dans les clusters.
Il en existe plusieurs implémentations dans di�érents langages (C,C++ (abandonné avec MPI-3), Fortran) mais peut aussi être appelédepuis Java, Python. . .
Une implémentation fournit un ensemble de fonctions permettant lacommunication et les échanges de données.
Calcul distribué
Introduction
Message Passing Interface
Principe d'un code utilisant MPI.
Plusieurs processus sont lancés en parallèle.
Chaque processus exécute le programme.
Le programme décrit le rôle de chaque processus.
La bibliothèque se focalise sur la synchronisation des processus etl'échange de données entre ceux-ci.
Calcul distribué
Introduction
Message Passing Interface
Un message MPI est constitué de :
un communicateur (essentiellement un ensemble de processus),
un identi�cateur du processus émetteur,
le type de la donnée transférée,
sa longueur,
la donnée elle même,
un identi�cateur du processus récepteur.
Tous ces constituants devront être présent à l'appel des fonctions MPI.
Calcul distribué
Introduction
Exemples de domaines d'applications
1 IntroductionMémoire partagéeMémoire distribuéeExemples de clustersMessage Passing InterfaceExemples de domaines d'applicationsQuelques liens
Calcul distribué
Introduction
Exemples de domaines d'applications
Prévisions météorologique,
Cryptographie,
Modélisation d'explosion nucléaire,
Astrophysique,
Dynamique des particules (calculs des interactions),
Pattern matching (comparaison d'ADN, traitement d'images).
Calcul distribué
Introduction
Quelques liens
1 IntroductionMémoire partagéeMémoire distribuéeExemples de clustersMessage Passing InterfaceExemples de domaines d'applicationsQuelques liens
Calcul distribué
Introduction
Quelques liens
Implémentations open source.
MPICH2 : http://www.mpich.org
OpenMPI : http://www.open-mpi.org
Documentation.
http://www.open-mpi.org/doc/v1.10/
http://www.mpi-forum.org/docs/
Machines.
http://top500.org/
http://green500.org/
Sources.
http://www.idris.fr/data/cours/parallel/mpi/IDRISMPI.pdf
Calcul distribué
Environnement
2 EnvironnementPremier exempleCompilation, exécutionComparaison avec OpenMPCommunicateur par défaut
Calcul distribué
Environnement
Premier exemple
2 EnvironnementPremier exempleCompilation, exécutionComparaison avec OpenMPCommunicateur par défaut
Calcul distribué
Environnement
Premier exemple
// intro/minimal.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(&argc, &argv);printf("Sup.\n");MPI_Finalize();
return 0;}
Tout programme faisant appel à MPI doit :
inclure <mpi.h>,
initialiser l'environnement avec MPI_Init,
désactiver l'environnement avec MPI_Finalize.
Calcul distribué
Environnement
Compilation, exécution
2 EnvironnementPremier exempleCompilation, exécutionComparaison avec OpenMPCommunicateur par défaut
Calcul distribué
Environnement
Compilation, exécution
$ mpicc -o source source.c
$ mpirun -n 2 source
mpicc n'est en fait qu'un appel élaboré à gcc :
mpicc -showme
L'option −n permet de préciser le nombre de processus à exécuter(en parallèle).
Si l'option −n est omise, le nombre de processus lancés dépend de lamachine.
La commande ci-dessus exécute source deux fois sur localhost eta�che :Sup.
Sup.
Calcul distribué
Environnement
Compilation, exécution
L'option −host permet de préciser les machines à utiliser.
mpirun -host host0,host1 source
exécute source une fois sur host0 et une fois sur host1.
On peut combiner −n et −host. Si le nombre de processus donné estsupérieur au nombre de machine, on remonte à la première machine.
mpirun -n 3 -host host0,host1 source
exécute source une fois sur host0, une fois sur host1, puis une autrefois sur host0.
Calcul distribué
Environnement
Compilation, exécution
On peut aussi utiliser l'option −host�le avec un �chier d'entrée.$ cat hostshost0 slots=2host1 slots=4
mpirun -n 7 -host�le hosts source
exécute source deux fois sur host0, quatre fois sur host1, puis unedernière fois sur host0.
man mpirun pour plus d'options et plus de détails sur le �chier hosts.
Calcul distribué
Environnement
Comparaison avec OpenMP
2 EnvironnementPremier exempleCompilation, exécutionComparaison avec OpenMPCommunicateur par défaut
Calcul distribué
Environnement
Comparaison avec OpenMP
OpenMP
Une seule instance du programme est exécutée : il n'y a qu'un seulprocessus.
Le processus se divise en plusieurs threads exécutés en parallèle.
Les parties parallèles sont délimités par des directives pré-processeurs(#pragma).
MPI
Plusieurs instances du programme sont exécutées en même temps :plusieurs processus sont créés.
Chaque processus exécute l'intégralité du programme, et lesprocessus s'exécutent en parallèle.
MPI_Init et MPI_Finalize ne correspondent pas aux début et �n dela partie parallélisée.
Calcul distribué
Environnement
Communicateur par défaut
2 EnvironnementPremier exempleCompilation, exécutionComparaison avec OpenMPCommunicateur par défaut
Calcul distribué
Environnement
Communicateur par défaut
Les processus lancés par mpirun doivent pouvoir communiquer entre eux.
Tous les processus sont reliés par le communicateur par défaut
MPI_COMM_WORLD.
MPI_COMM_WORLD est créé par MPI_Init et détruit par MPI_Finalize.
Chaque processus a un rang qui l'identi�e dans MPI_COMM_WORLD.
C'est grâce à ce rang qu'on e�ectue le partage des tâches.
Toutes les communications entre processus passent par uncommunicateur.
Calcul distribué
Environnement
Communicateur par défaut
// intro/default_comm.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(&argc, &argv);
int world_size;MPI_Comm_size(MPI_COMM_WORLD, &world_size);
int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);if (wrank!=1)
printf("Rang %d sur %d.\n", wrank, world_size);
MPI_Finalize();return 0;
}
Calcul distribué
Environnement
Communicateur par défaut
$ mpirun -n 4 sourceRang 2 sur 4.Rang 0 sur 4.Rang 3 sur 4.
Chaque processus de rang 6= 1 appelle printf (une seule fois) avecson rang.
L'ordre de sortie est indé�ni.
Calcul distribué
Communications point à point
3 Communications point à pointPrincipeExemplePrécisions sur le tagTypes de données de baseRemarques
Calcul distribué
Communications point à point
Principe
3 Communications point à pointPrincipeExemplePrécisions sur le tagTypes de données de baseRemarques
Calcul distribué
Communications point à point
Principe
Une communication dite point à point a lieu entre deux processus :l'émetteur et le récepteur (ou destinataire).
L'émetteur et le récepteur sont identi�és par leur rang dans lecommunicateur.L'enveloppe d'un message est constituée :
du communicateur (qui doit contenir les deux processus),du rang du processus émetteur,du rang du processus récepteur,de l'étiquette (un identi�ant) du message.
Il faut préciser le type des données communiquées.
Il existe plusieurs modes de transfert.
Calcul distribué
Communications point à point
Exemple
3 Communications point à pointPrincipeExemplePrécisions sur le tagTypes de données de baseRemarques
Calcul distribué
Communications point à point
Exemple
int MPI_Ssend(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);
comm : le communicateur.
tag : l'identi�ant du message.
dest/source : le rang du processus récepteur/émetteur dans lecommunicateur comm.
datatype : le type des données à envoyer/recevoir.
count : le nombre de données de type datatype à envoyer/recevoir.
buf : l'adresse du début des données à envoyer/recevoir.
Calcul distribué
Communications point à point
Exemple
// intro/send-receive.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(&argc, &argv);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int witness = 0;if (wrank==2){
int modifier = 1;MPI_Ssend(&modifier, 1, MPI_INT, 3, 28, MPI_COMM_WORLD);
}else if (wrank==3)
MPI_Recv(&witness, 1, MPI_INT, 2, 28, MPI_COMM_WORLD,MPI_STATUS_IGNORE);
printf("Rang %d, witness %d.\n", wrank, witness);MPI_Finalize();return 0;
}
Calcul distribué
Communications point à point
Exemple
$ mpirun -n 4 sourceRang 1, witness 0.Rang 0, witness 0.Rang 2, witness 0.Rang 3, witness 1.
Pour passer plusieurs valeurs :
// intro/send-receive.cint witness[] = {0, 0};if (wrank==2){
int modifier[] = {1, 1};MPI_Ssend(modifier, 2, MPI_INT, 3, 28, MPI_COMM_WORLD);
}else if (wrank==3)
MPI_Recv(witness, 2, MPI_INT, 2, 28, MPI_COMM_WORLD,MPI_STATUS_IGNORE);
Calcul distribué
Communications point à point
Exemple
Pour toutes les communications, il faut préciser à la fois un typepour l'émission et un type pour la réception.
Le tag de MPI_Ssend doit correspondre à celui de MPI_Recv, sinon lacommunication échoue.
Le transfert de données se fait grâce à un simple �ux d'octets (pasde données sur le type).
C'est au programmeur de véri�er que les types d'émission et deréception sont les mêmes, ou au moins qu'ils sont compatibles (voirexemples frames 153 et 158).
Note.
La communication réussira si le nombre d'octets émis est égal aunombre d'octets reçus. Ainsi, on peut par exemple envoyer untableau de deux int et recevoir un seul long ou même un seul double.
Calcul distribué
Communications point à point
Précisions sur le tag
3 Communications point à pointPrincipeExemplePrécisions sur le tagTypes de données de baseRemarques
Calcul distribué
Communications point à point
Précisions sur le tag
Le tag doit être un entier compris entre 0 et une valeur dépendantedu système, obtenu par le programme suivant.
// tag.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(&argc, &argv);int flag;int* max_tag;MPI_Comm_get_attr(MPI_COMM_WORLD, MPI_TAG_UB,
&max_tag, &flag);printf("Maximum tag : %d.\n", *max_tag);MPI_Finalize();
return 0;}
Ce maximum est toujours ≥ 32767.
Calcul distribué
Communications point à point
Précisions sur le tag
Réutiliser le même tag pour plusieurs communications successivesn'est pas un problème : l'ordre de réception est le même que
l'ordre d'envoi, quelque soit le mode de communication.
À la réception d'un message, le rang de l'émetteur et l'étiquettepeuvent être des � jokers �, respectivement MPI_ANY_SOURCE etMPI_ANY_TAG.
Calcul distribué
Communications point à point
Types de données de base
3 Communications point à pointPrincipeExemplePrécisions sur le tagTypes de données de baseRemarques
Calcul distribué
Communications point à point
Types de données de base
Type MPI Type C Taille des types C (octets)MPI_CHAR char 1
MPI_SHORT short 2
MPI_INT int 4
MPI_LONG long int 8
MPI_UNSIGNED_CHAR unsigned char 1
MPI_UNSIGNED_SHORT unsigned short 2
MPI_UNSIGNED unsigned int 4
MPI_UNSIGNED_LONG unsigned long int 8
MPI_FLOAT float 4
MPI_DOUBLE double 8
MPI_LONG_DOUBLE long double 16
Tous les types MPI_* ont pour taille 8 octets.
Calcul distribué
Communications point à point
Remarques
3 Communications point à pointPrincipeExemplePrécisions sur le tagTypes de données de baseRemarques
Calcul distribué
Communications point à point
Remarques
Le processus récepteur ne sort de l'appel à MPI_Recv que lorsquel'intégralité du message du tag spéci�é a été reçu.
Le comportement du processus émetteur est plus compliqué (voirsection 7).
MPI_STATUS_IGNORE est une constante prédé�nie qui peut être utiliséeà la place de la variable statut.
On peut créer et communiquer des structures de données pluscomplexes (voir frame 165).
Calcul distribué
Communications collectives
4 Communications collectivesNotions généralesSynchronisation globale : MPI_BarrierDi�usion générale : MPI_BcastDi�usion sélective : MPI_ScatterCollecte : MPI_GatherCollecte générale : MPI_AllgatherDi�usion : MPI_ScattervCollecte : MPI_GathervCollectes et di�usions sélectives : MPI_Alltoall
Calcul distribué
Communications collectives
Notions générales
4 Communications collectivesNotions généralesSynchronisation globale : MPI_BarrierDi�usion générale : MPI_BcastDi�usion sélective : MPI_ScatterCollecte : MPI_GatherCollecte générale : MPI_AllgatherDi�usion : MPI_ScattervCollecte : MPI_GathervCollectes et di�usions sélectives : MPI_Alltoall
Calcul distribué
Communications collectives
Notions générales
Les communications collectives permettent de faire en une seuleopération une série de communications point à point.
Une communication collective concerne toujours tous les processusdu communicateur indiqué.
Pour chacun des processus, l'appel se termine lorsque la participationde celui-ci à l'opération collective est achevée, au sens descommunications point-à-point.
On ne dé�nit jamais les étiquettes explicitement ; le système les gèrede manière transparente. Avantage : les communications collectivesn'interfèrent jamais avec les communications point à point.
Calcul distribué
Communications collectives
Notions générales
Il y a trois types de communications collectives.
1 Synchronisation globale : MPI_Barrier.2 Transfert de données uniquement :
di�usion globale de données : MPI_Bcast,di�usion sélective de données : MPI_Scatter, MPI_Scatterv,collecte de données réparties : MPI_Gather, MPI_Gatherv,collecte par tous les processus de données réparties : MPI_Allgather,collecte et di�usion sélective, par tous les processus, de donnéesréparties : MPI_Alltoall.
3 Transfert et e�ectue des opérations sur des données :réduction (somme, produit, maximum, minimum, etc.), qu'elles soientd'un type prédé�ni ou d'un type personnel : MPI_Reduce,réduction avec di�usion du résultat (équivalent à un MPI_Reduce suivid'un MPI_Bcast ) : MPI_Allreduce.
Calcul distribué
Communications collectives
Synchronisation globale : MPI_Barrier
4 Communications collectivesNotions généralesSynchronisation globale : MPI_BarrierDi�usion générale : MPI_BcastDi�usion sélective : MPI_ScatterCollecte : MPI_GatherCollecte générale : MPI_AllgatherDi�usion : MPI_ScattervCollecte : MPI_GathervCollectes et di�usions sélectives : MPI_Alltoall
Calcul distribué
Communications collectives
Synchronisation globale : MPI_Barrier
int MPI_Barrier(MPI_Comm comm);
Barrier
P1
P3 P0 P1 P2 P3
P2
P0
attente des processus 0, 1, 2.
Tous les processus ont
Les processus reprennent
Processus 3 bloqué en
atteints la barrière.
leurs exécutions.
P0
P1
P2
P3
Tous les processus du communicateur doivent appeler la fonctionMPI_Barrier.
Un processus qui appelle la fonction reste bloqué et doit attendreque tous les autres processus du communicateur l'appellent.
Lorsque tous les processus du communicateur ont appelé la fonction,tous reprennent ensemble leurs exécutions.
Calcul distribué
Communications collectives
Synchronisation globale : MPI_Barrier
// collectives/barrier.c#include <mpi.h>#include <stdio.h>#include <time.h>
int main(int argc, char ** argv){
MPI_Init(&argc, &argv);
int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
if (wrank==0){
FILE* f = fopen("outin", "w");long int seconds = time(NULL);fprintf(f, "%ld", seconds);fclose(f);
}
MPI_Barrier(MPI_COMM_WORLD);
Calcul distribué
Communications collectives
Synchronisation globale : MPI_Barrier
long int witness = 0;FILE* f = fopen("outin", "r");fscanf(f, "%d", &witness);printf("Rang %d, witness %ld.\n", wrank, witness);fclose(f);
MPI_Finalize();return 0;
}
$ mpirun -n 4 sourceRang 1, witness 1450259857.Rang 0, witness 1450259857.Rang 2, witness 1450259857.
Rang 3, witness 1450259857.
Calcul distribué
Communications collectives
Synchronisation globale : MPI_Barrier
Sortie possible si on enlève l'appel à MPI_Barrier.
$ mpirun -n 4 sourceRang 1, witness 1450259857.Rang 3, witness 1450259857.Rang 0, witness 1450259860.
Rang 2, witness 1450259860.
Dans ce cas, les processus 1 et 3 ont lu le �chier avant que celui-cine soit modi�é par le processus 0, et ils récupèrent donc la valeurcontenue dans le �chier avant l'exécution du programme.
Les processus 0 et 2 ont lu le �chier après modi�cation, etrécupèrent donc la nouvelle valeur.
Calcul distribué
Communications collectives
Synchronisation globale : MPI_Barrier
Remarques
La fonction MPI_Barrier ne prend pas d'identi�ant de message enargument. La conséquence est que les processus peuvent appeler desMPI_Barrier di�érents (situés à di�érents endroits du programme).Ainsi, le code
if (wrank==0)MPI_Barrier(MPI_COMM_WORLD);
elseMPI_Barrier(MPI_COMM_WORLD);
aura le même e�et que
MPI_Barrier(MPI_COMM_WORLD);
Calcul distribué
Communications collectives
Synchronisation globale : MPI_Barrier
En interne, MPI_Barrier e�ectue les étapes suivantes :Chaque processus de rang 6= 0 envoie un message vide au processusde rang 0 et attend une réponse,le processus de rang 0 attend d'avoir reçu des messages de tous lesprocessus (sauf lui même),lorsque le processus 0 a reçu tous les messages, il envoie une réponse(un autre message vide) à tous les processus, leur signalant ainsi quetous les processus ont atteints une barrière,les processus 6= 0 quittent MPI_Barrier à la reception de cetteréponse,le processus 0 quitte MPI_Barrier après l'envoi de toutes les réponses.
MPI_Barrier est l'unique fonction qui permet d'assurer lasynchronisation entre les processus. En particulier, aucune desopérations collectives présentées par la suite n'assure lasynchronisation.
Calcul distribué
Communications collectives
Di�usion générale : MPI_Bcast
4 Communications collectivesNotions généralesSynchronisation globale : MPI_BarrierDi�usion générale : MPI_BcastDi�usion sélective : MPI_ScatterCollecte : MPI_GatherCollecte générale : MPI_AllgatherDi�usion : MPI_ScattervCollecte : MPI_GathervCollectes et di�usions sélectives : MPI_Alltoall
Calcul distribué
Communications collectives
Di�usion générale : MPI_Bcast
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype,
int root, MPI_Comm comm);
P0
P1
P2
P3
count
Tous les processus du communicateur doivent appeler la fonctionMPI_Bcast.
Le processus de rang root est l'unique émetteur, tous sont récepteurs.
Après l'appel, les count données de type datatype pointées par buffersont égales pour tous les processus.
Calcul distribué
Communications collectives
Di�usion générale : MPI_Bcast
// collectives/bcast.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(&argc, &argv);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int witness = wrank;MPI_Bcast(&witness, 1, MPI_INT, 2, MPI_COMM_WORLD);
printf("Rang %d, witness %d.\n", wrank, witness);MPI_Finalize();return 0;
}
$ mpirun -n 4 sourceRang 1, witness 2.Rang 0, witness 2.Rang 2, witness 2.
Rang 3, witness 2.
Calcul distribué
Communications collectives
Di�usion sélective : MPI_Scatter
4 Communications collectivesNotions généralesSynchronisation globale : MPI_BarrierDi�usion générale : MPI_BcastDi�usion sélective : MPI_ScatterCollecte : MPI_GatherCollecte générale : MPI_AllgatherDi�usion : MPI_ScattervCollecte : MPI_GathervCollectes et di�usions sélectives : MPI_Alltoall
Calcul distribué
Communications collectives
Di�usion sélective : MPI_Scatter
int MPI_Scatter(const void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,
int root, MPI_Comm comm);
P0
P1
P2
P3
Tous les processus du communicateur doivent appeler la fonctionMPI_Scatter.
Le processus de rang root est l'unique emetteur, tous sont récepteurs.
sendcount est le nombre de données émises à un seul processus.
Calcul distribué
Communications collectives
Di�usion sélective : MPI_Scatter
MPI_Scatter découpe la donnée à envoyer en plusieurs (autant que deprocessus dans le communicateur) morceaux de taille sendcount.L'ordre des données envoyés correspond à l'ordre des rangs desprocessus récepteurs : le ième jeu de données est envoyé auprocessus de rang i .Le nombre total de données émises est sendcount * (nombre deprocessus dans le communicateur).sendcount*sizeof(sendtype (en C)) == recvcount*sizeof(recvtype
(en C))
// collectives/scatter.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(NULL, NULL);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
Calcul distribué
Communications collectives
Di�usion sélective : MPI_Scatter
int array[] = {wrank, 2*wrank, 3*wrank, 4*wrank};int witness=0;MPI_Scatter(array, 1, MPI_INT,
&witness, 1, MPI_INT, 2, MPI_COMM_WORLD);printf("Rang %d, witness %d.\n", wrank, witness);MPI_Finalize();return 0;
}
$ mpirun -n 4 sourceRang 0, witness 2.Rang 1, witness 4.Rang 2, witness 6.
Rang 3, witness 8.
Calcul distribué
Communications collectives
Collecte : MPI_Gather
4 Communications collectivesNotions généralesSynchronisation globale : MPI_BarrierDi�usion générale : MPI_BcastDi�usion sélective : MPI_ScatterCollecte : MPI_GatherCollecte générale : MPI_AllgatherDi�usion : MPI_ScattervCollecte : MPI_GathervCollectes et di�usions sélectives : MPI_Alltoall
Calcul distribué
Communications collectives
Collecte : MPI_Gather
int MPI_Gather(const void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,
int root, MPI_Comm comm);
P0
P1
P2
P3
C'est l'opération inverse de MPI_Scatter.
root est l'unique récepteur, tous sont émetteurs.
sendcount est le nombre de données émises par un seul processus.
Les données sont collectées dans l'ordre des rangs des processus.
Mêmes contraintes que MPI_Scatter sur les tailles des données.
Calcul distribué
Communications collectives
Collecte : MPI_Gather
// collectives/gather.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(NULL, NULL);
int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int witness[] = {0, 0, 0, 0};MPI_Gather(&wrank, 1, MPI_INT,
witness, 1, MPI_INT, 2, MPI_COMM_WORLD);printf("Rang %d, witness", wrank);
for (int i=0; i<4; ++i)printf(" %d", witness[i]);
printf(".\n");
MPI_Finalize();return 0;
}
Calcul distribué
Communications collectives
Collecte : MPI_Gather
$ mpirun -n 4 sourceRang 0, witness 0 0 0 0.Rang 3, witness 0 0 0 0.Rang 1, witness 0 0 0 0.
Rang 2, witness 0 1 2 3.
Calcul distribué
Communications collectives
Collecte générale : MPI_Allgather
4 Communications collectivesNotions généralesSynchronisation globale : MPI_BarrierDi�usion générale : MPI_BcastDi�usion sélective : MPI_ScatterCollecte : MPI_GatherCollecte générale : MPI_AllgatherDi�usion : MPI_ScattervCollecte : MPI_GathervCollectes et di�usions sélectives : MPI_Alltoall
Calcul distribué
Communications collectives
Collecte générale : MPI_Allgather
int MPI_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,
MPI_Comm comm);
P0
P1
P2
P3
Tous les processus sont émetteurs, et tous sont récepteurs.
sendcount est le nombre de données émises par un processus, pour
un processus.
Les données sont collectées dans l'ordre des rangs des processus.
Revient à faire MPI_Gather avec le processus 0 comme récepteur, suivide MPI_Gather avec le processus 1 comme récepteur, et ainsi de suitepour tous les processus.
Calcul distribué
Communications collectives
Collecte générale : MPI_Allgather
// collectives/allgather.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(NULL, NULL);
int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int witness[] = {0, 0, 0, 0};MPI_Allgather(&wrank, 1, MPI_INT,
witness, 1, MPI_INT, MPI_COMM_WORLD);printf("Rang %d, witness", wrank);
for (int i=0; i<4; ++i)printf(" %d", witness[i]);
printf(".\n");
MPI_Finalize();return 0;
}
Calcul distribué
Communications collectives
Collecte générale : MPI_Allgather
$ mpirun -n 4 sourceRang 0, witness 0 1 2 3.Rang 3, witness 0 1 2 3.Rang 2, witness 0 1 2 3.
Rang 1, witness 0 1 2 3.
Calcul distribué
Communications collectives
Di�usion : MPI_Scatterv
4 Communications collectivesNotions généralesSynchronisation globale : MPI_BarrierDi�usion générale : MPI_BcastDi�usion sélective : MPI_ScatterCollecte : MPI_GatherCollecte générale : MPI_AllgatherDi�usion : MPI_ScattervCollecte : MPI_GathervCollectes et di�usions sélectives : MPI_Alltoall
Calcul distribué
Communications collectives
Di�usion : MPI_Scatterv
int MPI_Scatterv(const void *sendbuf, const int sendcounts[], const int displs[],MPI_Datatype sendtype, void *recvbuf, int recvcount,
MPI_Datatype recvtype, int root, MPI_Comm comm);
P0
P1
P2
P3
0 1 3 4
indices
Même fonctionnement et propriétés que MPI_Scatter, mais on peutrégler le nombre et l'emplacement des données émises avec lesarguments sendcounts et displs (displacements / o�sets).
Les deux arguments sendcounts et displs ne servent que pour leprocessus émetteur.
La taille sendcounts et displs est le nombre de processus dans lecommunicateur.
Calcul distribué
Communications collectives
Di�usion : MPI_Scatterv
P0
P1
P2
P3
0 1 3 4
indices
P0 P1 P2 P3recvcount 1 2 1 2
Seulement pour P2 :
sendbuf de taille 1+ 2+ 1+ 2 = 6,
sendcounts = {1, 2, 1, 2}
displs = {0, 1, 3, 4}.
Calcul distribué
Communications collectives
Di�usion : MPI_Scatterv
// collectives/scatterv.c#include <mpi.h>#include <stdio.h>#include <stdlib.h>
int main(int argc, char **argv){
MPI_Init(NULL, NULL);
int world_size, wrank;MPI_Comm_size(MPI_COMM_WORLD, &world_size);MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int recvbuf[] = {wrank, wrank};int recvcount = (wrank%2) + 1;int *sendbuf, *sendcounts, *displs;int total = 6;if (wrank==2){
sendcounts = (int*) calloc(world_size, sizeof(int));for (int i=0; i<world_size; ++i)
sendcounts[i]= (i%2) + 1;
Calcul distribué
Communications collectives
Di�usion : MPI_Scatterv
displs = (int*) calloc(world_size, sizeof(int));displs[0] = 0;for (int i=1; i<world_size; ++i)
displs[i] = displs[i-1] + sendcounts[i-1];
sendbuf = (int*) calloc(total, sizeof(int));for (int i=0; i<total; ++i)
sendbuf[i] = 28+i;}
MPI_Scatterv(sendbuf, sendcounts, displs, MPI_INT, recvbuf,recvcount, MPI_INT, 2, MPI_COMM_WORLD);
printf("Rang %d, recvbuf %d %d.\n", wrank, recvbuf[0], recvbuf[1]);
if (wrank==2){
free(sendcounts);free(displs);free(sendbuf);
}
Calcul distribué
Communications collectives
Di�usion : MPI_Scatterv
MPI_Finalize();return 0;
}
$ mpirun -n 4 sourceRang 0, recvbuf 28 0.Rang 1, recvbuf 29 30.Rang 2, recvbuf 31 2.
Rang 3, recvbuf 32 33.
Calcul distribué
Communications collectives
Collecte : MPI_Gatherv
4 Communications collectivesNotions généralesSynchronisation globale : MPI_BarrierDi�usion générale : MPI_BcastDi�usion sélective : MPI_ScatterCollecte : MPI_GatherCollecte générale : MPI_AllgatherDi�usion : MPI_ScattervCollecte : MPI_GathervCollectes et di�usions sélectives : MPI_Alltoall
Calcul distribué
Communications collectives
Collecte : MPI_Gatherv
int MPI_Gatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, const int recvcounts[], const int displs[],
MPI_Datatype recvtype, int root, MPI_Comm comm);
P0
P1
P2
P3
0 1 3 4
indices
Même fonctionnement et propriétés que MPI_Gather, mais on peutrégler le nombre et l'emplacement des données reçues avec lesarguments recvcounts et displs (displacements / o�sets).
Les deux arguments recvcounts et displs ne servent que pour leprocessus récepteur.
La taille recvcounts et displs est le nombre de processus dans lecommunicateur.
Calcul distribué
Communications collectives
Collecte : MPI_Gatherv
P0
P1
P2
P3
0 1 3 4
indices
P0 P1 P2 P3sendcount 1 2 1 2
Seulement pour P2 :
recvbuf de taille 1+ 2+ 1+ 2 = 6,
recvcounts = {1, 2, 1, 2}
displs = {0, 1, 3, 4}.
Calcul distribué
Communications collectives
Collecte : MPI_Gatherv
// collectives/gatherv.c#include <mpi.h>#include <stdio.h>#include <stdlib.h>
int main(int argc, char** argv){
MPI_Init(NULL, NULL);int world_size, wrank;MPI_Comm_size(MPI_COMM_WORLD, &world_size);MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int sendbuf[] = {wrank, wrank};int sendcount = (wrank%2) + 1;int *recvbuf, *recvcounts, *displs;int total = 6;if (wrank==2){
recvcounts = (int*) calloc(world_size, sizeof(int));for (int i=0; i<world_size; ++i)
recvcounts[i]= (i%2) + 1;
Calcul distribué
Communications collectives
Collecte : MPI_Gatherv
displs = (int*) calloc(world_size, sizeof(int));displs[0] = 0;for (int i=1; i<world_size; ++i)
displs[i] = displs[i-1] + recvcounts[i-1];
recvbuf = (int*) calloc(total, sizeof(int));}
MPI_Gatherv(sendbuf, sendcount, MPI_INT, recvbuf,recvcounts, displs, MPI_INT, 2, MPI_COMM_WORLD);
if (wrank==2){
for (int i=0; i<total; ++i)printf("%d ", recvbuf[i]);
printf("\n");
free(recvcounts);free(displs);free(recvbuf);
}
Calcul distribué
Communications collectives
Collecte : MPI_Gatherv
MPI_Finalize();return 0;
}
$ mpirun -n 4 source0 1 1 2 3 3.
Calcul distribué
Communications collectives
Collectes et di�usions sélectives : MPI_Alltoall
4 Communications collectivesNotions généralesSynchronisation globale : MPI_BarrierDi�usion générale : MPI_BcastDi�usion sélective : MPI_ScatterCollecte : MPI_GatherCollecte générale : MPI_AllgatherDi�usion : MPI_ScattervCollecte : MPI_GathervCollectes et di�usions sélectives : MPI_Alltoall
Calcul distribué
Communications collectives
Collectes et di�usions sélectives : MPI_Alltoall
int MPI_Alltoall(const void *sendbuf, int sendcount, MPI_Datatype sendtype,void *recvbuf, int recvcount, MPI_Datatype recvtype,
MPI_Comm comm);
a b c d
a b c d
a b c d
a b c d
a
b
c
d
a
b
c
d
a
b
c
d
a
b
c
d
P0
P1
P2
P3
Correspond à un MPI_Allgather où la donnée envoyée dépend duprocessus récepteur.
Le ième processus envoie le jème jeu de données au jème processusqui le place dans à la ième place.
Calcul distribué
Communications collectives
Collectes et di�usions sélectives : MPI_Alltoall
// collectives/alltoall.c#include <math.h>#include <mpi.h>#include <stdio.h>#include <stdlib.h>
int main(int argc, char** argv){
MPI_Init(NULL, NULL);
int world_size, wrank;MPI_Comm_size(MPI_COMM_WORLD, &world_size);MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int power = pow(10, wrank+1);int sendbuf[] = {power, power+1, power+2, power+3};int recvbuf[] = {0, 0, 0, 0};
MPI_Alltoall(sendbuf, 1, MPI_INT,recvbuf, 1, MPI_INT, MPI_COMM_WORLD);
Calcul distribué
Communications collectives
Collectes et di�usions sélectives : MPI_Alltoall
printf("Rang %d, recvbuf", wrank);for (int i=0; i<world_size; ++i)
printf(" %d", recvbuf[i]);printf(".\n");
MPI_Finalize();return 0;
}
$ mpirun -n 4 sourceRang 0, recvbuf 10 100 1000 10000.Rang 1, recvbuf 11 101 1001 10001.Rang 2, recvbuf 12 102 1002 10002.
Rang 3, recvbuf 13 103 1003 10003.
Calcul distribué
Distribution équitable
5 Distribution équitableExtension du tableau et MPI_Scatter
Distribution sous-optimale avec MPI_Scatterv
Distribution optimale avec MPI_Scatterv
Calcul distribué
Distribution équitable
On veut distribuer le plus équitablement possible un tableau T à Néléments sur P processus.
Si P divise N, on utilise simplement MPI_Scatter : le processusémetteur envoie N/P éléments à chaque processus.
Si P ne divise pas N, on ne peut pas utiliser MPI_Scatterdirectement, mais on peut utiliser MPI_Scatterv.
Dans tous les cas, il faut déterminer au préalable le nombred'éléments à envoyer à chaque processus.
Calcul distribué
Distribution équitable
Extension du tableau et MPI_Scatter
5 Distribution équitableExtension du tableau et MPI_Scatter
Distribution sous-optimale avec MPI_Scatterv
Distribution optimale avec MPI_Scatterv
Calcul distribué
Distribution équitable
Extension du tableau et MPI_Scatter
Soit N ′ le plus petit entier > N divisible par P . En C, avec unedivision entière,
N’ = (N/P + 1) * P;
On étend le tableau T en un tableau T ′ de taille N ′ : les N premierséléments des deux tableaux sont les mêmes, et on remplit T ′ avecdes valeurs neutres (des 0 si on compte sommer les éléments, 1 sion veut les multiplier. . .).
On utilise MPI_Scatter sur T ′ et on envoie N ′/P éléments à chaqueprocessus.
33 13 54 69 5 74 74 57 67 5
33 13 54 69 5 74 74 57 67 5
**
T
T’
N = 10
N’ = 12
P = 3
Calcul distribué
Distribution équitable
Distribution sous-optimale avec MPI_Scatterv
5 Distribution équitableExtension du tableau et MPI_Scatter
Distribution sous-optimale avec MPI_Scatterv
Distribution optimale avec MPI_Scatterv
Calcul distribué
Distribution équitable
Distribution sous-optimale avec MPI_Scatterv
Tous les processus à part un reçoivent N/P éléments de T .
On choisit un processus, en général l'émetteur, pour recevoir ce quireste, soit
N/P + N%P;
éléments.
33 13 54 69 5 74 74 57 67 5T 28 N = 11 P = 3
Le processus choisi reçoit entre 1 et P − 1 éléments de plus que lesautres.
Calcul distribué
Distribution équitable
Distribution optimale avec MPI_Scatterv
5 Distribution équitableExtension du tableau et MPI_Scatter
Distribution sous-optimale avec MPI_Scatterv
Distribution optimale avec MPI_Scatterv
Calcul distribué
Distribution équitable
Distribution optimale avec MPI_Scatterv
On choisit N%P processus, en général ceux de faibles rangs, pourrecevoir N/P + 1 éléments du tableau.
Les autres processus reçoivent N/P éléments.
33 13 54 69 5 74 74 57 67 5T 28 N = 11 P = 3
La di�érence de nombre d'éléments reçus pour deux processus est aumaximum 1.
Calcul distribué
Communications collectives : réductions
6 Communications collectives : réductionsRéductions réparties : MPI_ReduceRéductions réparties : MPI_Reduce, MPI_SUM
Réductions réparties : MPI_Reduce, MPI_MAXLOC
Réductions réparties : MPI_Allreduce
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Reduce
6 Communications collectives : réductionsRéductions réparties : MPI_ReduceRéductions réparties : MPI_Reduce, MPI_SUM
Réductions réparties : MPI_Reduce, MPI_MAXLOC
Réductions réparties : MPI_Allreduce
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Reduce
Une réduction est une opération appliquée à un ensembled'éléments pour en obtenir une seule valeur. Par exemple,somme/maximum d'éléments venant de plusieurs processus.
int MPI_Reduce(const void *sendbuf, void *recvbuf, int count,
MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm);
P0
P1
P2
P3 1000
100
10
1
1000
maximum
P0
P1
P2
P3 1000
100
10
1
1111
somme
L'argument op permet de choisir l'opération de réduction. Voir frame106 pour la liste des opérations prédé�nies.
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Reduce
Si chaque processus envoie un tableau, la fonction de réduction estappliquée pour chaque indice.
P0
P1
P2
P3 1000 2000
100 200
2010
1 2
1111 2222
somme
P0
P1
P2
P3 1000 2000
100 200
2010
1 2
maximum
1000 2000
Les fonctions MPI_Op_create et MPI_Op_free permettent de dé�nir desopérations de réductions personnelles.
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Reduce
Principales opérations de réduction prédé�nies.
Nom OpérationMPI_SUM Somme des élémentsMPI_PROD Produit des élémentsMPI_MAX Maximum des élémentsMPI_MIN Minimum des élémentsMPI_MAXLOC Maximum + indice (voir exemple)MPI_MINLOC Minimum + indice (voir exemple)MPI_LAND ET logiqueMPI_LOR OU logiqueMPI_LXOR OU exclusif logique
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Reduce, MPI_SUM
6 Communications collectives : réductionsRéductions réparties : MPI_ReduceRéductions réparties : MPI_Reduce, MPI_SUM
Réductions réparties : MPI_Reduce, MPI_MAXLOC
Réductions réparties : MPI_Allreduce
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Reduce, MPI_SUM
// collectives/reduce_sum.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(NULL, NULL);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int seeds[] = {wrank, 2*wrank};int sums[] = {0, 0};MPI_Reduce(&seeds, &sums, 2, MPI_INT, MPI_SUM, 2, MPI_COMM_WORLD);
printf("Rang %d, sums %d %d.\n", wrank, sums[0], sums[1]);MPI_Finalize();return 0;
}
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Reduce, MPI_SUM
$ mpirun -n 4 sourceRang 1, sums 0 0.Rang 0, sums 0 0.Rang 2, sums 6 12.
Rang 3, sums 0 0.
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Reduce, MPI_MAXLOC
6 Communications collectives : réductionsRéductions réparties : MPI_ReduceRéductions réparties : MPI_Reduce, MPI_SUM
Réductions réparties : MPI_Reduce, MPI_MAXLOC
Réductions réparties : MPI_Allreduce
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Reduce, MPI_MAXLOC
// collectives/reduce_maxloc.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(NULL, NULL);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);struct{
double val;int rank;
} in, out;
in.val = 10*wrank;in.rank = wrank;
MPI_Reduce(&in, &out, 1, MPI_DOUBLE_INT, MPI_MAXLOC, 2,MPI_COMM_WORLD);
printf("Rang %d, out %f %d.\n", wrank, out.val, out.rank);MPI_Finalize();return 0;
}
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Reduce, MPI_MAXLOC
$ mpirun -n 4 sourceRang 0, out 0.000000 0.Rang 3, out 0.000000 0.Rang 2, out 30.000000 3.
Rang 1, out 0.000000 0.
Utile pour savoir d'où vient le maximum.
Il existe d'autres types de paires MPI : MPI_FLOAT_INT, MPI_LONG_INT,
MPI_DOUBLE_INT, MPI_SHORT_INT, MPI_2INT, MPI_LONG_DOUBLE_INT.
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Allreduce
6 Communications collectives : réductionsRéductions réparties : MPI_ReduceRéductions réparties : MPI_Reduce, MPI_SUM
Réductions réparties : MPI_Reduce, MPI_MAXLOC
Réductions réparties : MPI_Allreduce
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Allreduce
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count,
MPI_Datatype datatype, MPI_Op op, MPI_Comm comm);
1111 2222
1111 2222
1111 2222
1111 2222P0
P1
P2
P3 1000 2000
100 200
2010
1 2
somme
Tous les processus calculent la réduction, et obtiennent donc lemême résultat.
// collectives/allreduce_sum.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(NULL, NULL);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
Calcul distribué
Communications collectives : réductions
Réductions réparties : MPI_Allreduce
int seeds[] = {wrank, 2*wrank};int sums[] = {0, 0};MPI_Allreduce(&seeds, &sums, 2, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
printf("Rang %d, sums %d %d.\n", wrank, sums[0], sums[1]);MPI_Finalize();return 0;
}
$ mpirun -n 4 sourceRang 1, sums 6 12.Rang 0, sums 6 12.Rang 2, sums 6 12.
Rang 3, sums 6 12.
Calcul distribué
Modes de communications
7 Modes de communicationsFonctionsCommunications bloquantesEnvoi bloquant, mode bu�eriséEnvoi bloquant, mode synchroneEnvoi bloquant, mode readyEnvoi bloquant, mode standardCommunications non bloquantes
Calcul distribué
Modes de communications
Fonctions
7 Modes de communicationsFonctionsCommunications bloquantesEnvoi bloquant, mode bu�eriséEnvoi bloquant, mode synchroneEnvoi bloquant, mode readyEnvoi bloquant, mode standardCommunications non bloquantes
Calcul distribué
Modes de communications
Fonctions
Bloquant Non bloquantEnvoi standard MPI_Send MPI_Isend
Envoi en mode bu�erisé MPI_Bsend MPI_Ibsend
Envoi en mode synchrone MPI_Ssend MPI_Issend
Envoi en mode ready MPI_Rsend MPI_Irsend
Réception MPI_Recv MPI_Irecv
Le mode utilisé par un envoi standard est décidé par MPI lors dechaque appel.
Les fonctions MPI_Send, MPI_Bsend, MPI_Ssend, MPI_Rsend ont toutesle même prototype (voir frame 41) et sont interchangeables dansl'exemple frame 42.
Les fonctions MPI_Isend, MPI_Ibsend, MPI_Issend, MPI_Irsend onttoutes le même prototype (voir frame 132) et sont interchangeablesdans l'exemple frame 132.
Calcul distribué
Modes de communications
Communications bloquantes
7 Modes de communicationsFonctionsCommunications bloquantesEnvoi bloquant, mode bu�eriséEnvoi bloquant, mode synchroneEnvoi bloquant, mode readyEnvoi bloquant, mode standardCommunications non bloquantes
Calcul distribué
Modes de communications
Communications bloquantes
On parle d'un appel bloquant lorsque l'espace mémoire servant à lacommunication (données + enveloppe) peut être réutilisé immédiatementaprès la sortie de l'appel.
Par � réutilisé �, on veut dire :
pour l'émetteur, les éléments du pointeur sur les données à envoyerpeuvent être modi�és, et le pointeur lui-même peut être libérer sansque cela in�ue sur la communication (typiquement, la fonction MPIa copié les données à transférer dans un bu�er temporaire, voir parexemple frame 123),
pour le récepteur, le pointeur sur les données à recevoir contientl'intégralité des données transmises et les éléments peuvent être lus.
Calcul distribué
Modes de communications
Communications bloquantes
Confusion sur le terme bloquant (malheureusement standard) pourl'émetteur.
Le terme s'applique à l'espace mémoire contenant les données àtransmettre, pas à la communication.
Le terme ne signi�e pas que l'émetteur attend la �n de lacommunication pour sortir de la fonction MPI.
L'émetteur peut même sortir de la fonction MPI avant que latransmission de données n'ait démarrée (voir frame 123).
Pas de confusion pour le récepteur.
Lorsque l'appel à la fonction MPI d'une réception bloquante termine,la communication est e�ectivement terminée.
Calcul distribué
Modes de communications
Envoi bloquant, mode bu�erisé
7 Modes de communicationsFonctionsCommunications bloquantesEnvoi bloquant, mode bu�eriséEnvoi bloquant, mode synchroneEnvoi bloquant, mode readyEnvoi bloquant, mode standardCommunications non bloquantes
Calcul distribué
Modes de communications
Envoi bloquant, mode bu�erisé
Lors d'un envoi en mode bu�erisé, le message et l'enveloppe sont copiésà un autre endroit de la mémoire du processus émetteur.
Fonction associée : MPI_Bsend.
L'appel à MPI_Bsend peut se faire même si le processus récepteurn'est pas encore en attente du message (il n'a pas atteint la fonctionde réception).
L'appel à MPI_Bsend peut se terminer même si la totalité du messagen'a pas été reçu, ou même si le processus récepteur n'a pas atteint lafonction de réception.
Si le processus récepteur est en attente du message lors de l'appel àMPI_Bsend, le bu�er peut être omis.
Calcul distribué
Modes de communications
Envoi bloquant, mode synchrone
7 Modes de communicationsFonctionsCommunications bloquantesEnvoi bloquant, mode bu�eriséEnvoi bloquant, mode synchroneEnvoi bloquant, mode readyEnvoi bloquant, mode standardCommunications non bloquantes
Calcul distribué
Modes de communications
Envoi bloquant, mode synchrone
Lors d'un envoi en mode synchrone, le processus émetteur doit attendreque la fonction de réception se termine.
Fonction associée : MPI_Ssend.
L'appel à MPI_Ssend peut se faire même si le processus récepteurn'est pas encore en attente du message (il n'a pas atteint la fonctionde réception).
C'est un bon moyen de synchroniser les deux processus.
Dans le cas d'une réception non bloquante (et uniquement dans cecas), la fonction de réception, et donc l'appel à MPI_Ssend, peuventse terminer sans que le message soit complètement transmis.
Calcul distribué
Modes de communications
Envoi bloquant, mode ready
7 Modes de communicationsFonctionsCommunications bloquantesEnvoi bloquant, mode bu�eriséEnvoi bloquant, mode synchroneEnvoi bloquant, mode readyEnvoi bloquant, mode standardCommunications non bloquantes
Calcul distribué
Modes de communications
Envoi bloquant, mode ready
Un envoi en mode ready n'est correct que si le processus récepteur estdéjà en attente du message.
Fonction associée : MPI_Rsend.
Permet d'omettre certaines opérations de communications, maisnécessite d'ordonnancer les processus.
Le comportement adopté lorsque le processus récepteur n'est pas enattente du message est indé�ni.
Très peu utilisé car très risqué.
Calcul distribué
Modes de communications
Envoi bloquant, mode standard
7 Modes de communicationsFonctionsCommunications bloquantesEnvoi bloquant, mode bu�eriséEnvoi bloquant, mode synchroneEnvoi bloquant, mode readyEnvoi bloquant, mode standardCommunications non bloquantes
Calcul distribué
Modes de communications
Envoi bloquant, mode standard
Le comportement exact du mode standard est décidé au moment del'envoi.
Fonction associée : MPI_Send.
Suivant la taille des données / l'avancement des processus, MPI_Sendse comportera soit comme un MPI_Bsend, soit comme un MPI_Ssend,soit comme un MPI_Rsend.
Il n'est pas possible de déterminer à l'avance son comportement.
Calcul distribué
Modes de communications
Communications non bloquantes
7 Modes de communicationsFonctionsCommunications bloquantesEnvoi bloquant, mode bu�eriséEnvoi bloquant, mode synchroneEnvoi bloquant, mode readyEnvoi bloquant, mode standardCommunications non bloquantes
Calcul distribué
Modes de communications
Communications non bloquantes
Un appel non bloquant démarre l'émission ou la réception d'un messagepuis termine immédiatement (le programme continue son exécution).
Permet de continuer les calculs pendant que la communications'e�ectue.
Tout appel non bloquant nécessite l'appel à la fonction MPI_Wait (ouune de ses déclinaisons) pour terminer correctement l'appel.
Dans le cas d'un envoi non bloquant, la mémoire contenant lemessage ne doit pas être réutilisée (mais peut être lue) avant l'appelà MPI_Wait.
Dans le cas d'une réception non bloquante, la mémoire destinée àrecevoir le message ne doit pas être lue avant l'appel à MPI_Wait.
Un envoi non bloquant peut être couplé à une réception bloquante etinversement.
Calcul distribué
Modes de communications
Communications non bloquantes
int MPI_Isend(const void *buf, int count, MPI_Datatype datatype,
int dest, int tag, MPI_Comm comm, MPI_Request *request);
int MPI_Irecv(void *buf, int count, MPI_Datatype datatype,
int source, int tag, MPI_Comm comm, MPI_Request *request);
int MPI_Wait(MPI_Request *request, MPI_Status *status);
// non-bloquant.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(NULL, NULL);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
Calcul distribué
Modes de communications
Communications non bloquantes
int witness = 0;MPI_Request request;if (wrank==2){
int modifier = 1;MPI_Isend(&modifier, 1, MPI_INT, 3, 28, MPI_COMM_WORLD,
&request);// Computations.MPI_Wait(&request, MPI_STATUS_IGNORE);
}else if (wrank==3){
MPI_Irecv(&witness, 1, MPI_INT, 2, 28, MPI_COMM_WORLD,&request);
// Other computations.MPI_Wait(&request, MPI_STATUS_IGNORE);
}
printf("Rang %d, witness %d.\n", wrank, witness);MPI_Finalize();return 0;
}
Calcul distribué
Modes de communications
Communications non bloquantes
$ mpirun -n 4 sourceRang 0, witness 0.Rang 2, witness 0.Rang 3, witness 1.
Rang 1, witness 0.
L'argument de type MPI_Request est un identi�ant de l'appel nonbloquant.
Il faut en allouer un par appel non bloquant.
Calcul distribué
Deadlocks
8 DeadlocksDé�nitionExemple
Calcul distribué
Deadlocks
Dé�nition
8 DeadlocksDé�nitionExemple
Calcul distribué
Deadlocks
Dé�nition
On est en situation de deadlock lorsqu'un processus attend indé�nimentune action d'un autre processus.
Peut arriver lors de communications bloquantes, ou lors d'appel àMPI_Wait.Ils peuvent être provoqués par :
un appel à MPI_Recv sans émission correspondante, soit parce qu'iln'y a simplement pas d'émission, soit à cause d'une erreur dansl'enveloppe de l'émission (un tag ou un processus émetteur incorrect),(le plus souvent) un ordonnancement incorrect des émissions /réceptions.
Note.
Puisque le mode utilisé par MPI_Send n'est décidé qu'à l'appel de lafonction, certains programmes ne provoqueront passystématiquement un deadlock, même si l'ordonnancement desémissions / réceptions est incorrect.
Calcul distribué
Deadlocks
Exemple
8 DeadlocksDé�nitionExemple
Calcul distribué
Deadlocks
Exemple
// possible-deadlock.c#include <mpi.h>
int main(int argc, char** argv){
MPI_Init(NULL, NULL);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
if (wrank==0){
int send0 = 10, recv0;MPI_Send(&send0, 1, MPI_INT, 1, 28, MPI_COMM_WORLD);MPI_Recv(&recv0, 1, MPI_INT, 1, 42, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);}else if (wrank==1){
int send1 = 11, recv1;MPI_Send(&send1, 1, MPI_INT, 0, 42, MPI_COMM_WORLD);MPI_Recv(&recv1, 1, MPI_INT, 0, 28, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);}
Calcul distribué
Deadlocks
Exemple
MPI_Finalize();return 0;
}
Si les deux appels à MPI_Send se font en mode synchrone, il y aura undeadlock.
Si un des appels se fait en mode bu�erisé, il n'y aura pas dedeadlock.
Calcul distribué
Deadlocks
Exemple
Le même programme avec des MPI_Ssend à la place des MPI_Send
provoquera systématiquement un deadlock.
Une des manières de s'assurer que l'ordonnancement descommunications est correct est d'utiliser des MPI_Ssend partout (maisle programme sera un peu plus lent).
Une bonne règle d'écriture de programme MPI est de mettre desMPI_Ssend partout dans un premier temps, puis de les remplacer pardes MPI_Send lorsqu'on est sûr que toutes les communicationss'e�ectuent correctement.
Calcul distribué
Types de données dérivés
9 Types de données dérivésIntroductionExtraction contiguë : MPI_Type_contiguousExtraction à pas constant : MPI_Type_vectorExtraction à pas variable : MPI_Type_indexedPaddingStructure de données MPI_Type_create_struct
Calcul distribué
Types de données dérivés
Introduction
9 Types de données dérivésIntroductionExtraction contiguë : MPI_Type_contiguousExtraction à pas constant : MPI_Type_vectorExtraction à pas variable : MPI_Type_indexedPaddingStructure de données MPI_Type_create_struct
Calcul distribué
Types de données dérivés
Introduction
Il est possible de créer ses propres types de données MPI.
Le type créé sera de type MPI_Datatype.
Tout type créé destiné à être utilisé pour une communication doitêtre enregistré à l'aide de la fonction MPI_Type_commit.int MPI_Type_commit(MPI_Datatype *datatype);
Tout type créé avec un MPI_Type_commit doit être libéré par unMPI_Type_free (surtout si on veut réutiliser le nom).int MPI_Type_free(MPI_Datatype *datatype);
Deux sortes de types peuvent être créés :extraction de données d'un tableau (MPI_Type_vector,MPI_Type_indexed),des types utilisés pour faire passer les structures qu'on dé�nit(MPI_Type_create_struct).
Calcul distribué
Types de données dérivés
Extraction contiguë : MPI_Type_contiguous
9 Types de données dérivésIntroductionExtraction contiguë : MPI_Type_contiguousExtraction à pas constant : MPI_Type_vectorExtraction à pas variable : MPI_Type_indexedPaddingStructure de données MPI_Type_create_struct
Calcul distribué
Types de données dérivés
Extraction contiguë : MPI_Type_contiguous
int MPI_Type_contiguous(int count, MPI_Datatype oldtype,
MPI_Datatype *newtype);
count
Le nombre total d'éléments de type oldtype contenu dans *newtype
est count.
Calcul distribué
Types de données dérivés
Extraction contiguë : MPI_Type_contiguous
// types/contiguous.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(&argc, &argv);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int data[24];for (int i=0; i<24; ++i)
data[i] = 0;
MPI_Datatype CType;MPI_Type_contiguous(8, MPI_INT, &CType);MPI_Type_commit(&CType);
if (wrank==0){
for (int i=0; i < 24; i++)data[i] = i;
MPI_Ssend(data+10, 1, CType, 1, 28, MPI_COMM_WORLD);}
Calcul distribué
Types de données dérivés
Extraction contiguë : MPI_Type_contiguous
else if (wrank==1){
MPI_Recv(data, 1, CType, 0, 28, MPI_COMM_WORLD,MPI_STATUS_IGNORE);
for (int i=0; i < 8; i++)printf("%d ", data[i]);
printf(".\n");}
MPI_Type_free(&CType);MPI_Finalize();return 0;
}
$ mpirun -n 2 source
10 11 12 13 14 15 16 17.
Calcul distribué
Types de données dérivés
Extraction à pas constant : MPI_Type_vector
9 Types de données dérivésIntroductionExtraction contiguë : MPI_Type_contiguousExtraction à pas constant : MPI_Type_vectorExtraction à pas variable : MPI_Type_indexedPaddingStructure de données MPI_Type_create_struct
Calcul distribué
Types de données dérivés
Extraction à pas constant : MPI_Type_vector
int MPI_Type_vector(int count, int blocklength, int stride,
MPI_Datatype oldtype, MPI_Datatype *newtype);
blocklength
stride
count est le nombre de blocks.
Le nombre total d'éléments de type oldtype contenu dans *newtype
est count*blocklength.
Calcul distribué
Types de données dérivés
Extraction à pas constant : MPI_Type_vector
// types/vector.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(&argc, &argv);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int data[24];for (int i=0; i<24; ++i)
data[i] = 0;
MPI_Datatype VType;MPI_Type_vector(4, 2, 6, MPI_INT, &VType);MPI_Type_commit(&VType);
if (wrank==0){
for (int i=0; i < 24; i++)data[i] = i;
MPI_Ssend(data, 1, VType, 1, 28, MPI_COMM_WORLD);}
Calcul distribué
Types de données dérivés
Extraction à pas constant : MPI_Type_vector
else if (wrank==1){
MPI_Recv(data, 1, VType, 0, 28, MPI_COMM_WORLD,MPI_STATUS_IGNORE);
for (int i=0; i < 24; i++)printf("%d ", data[i]);
printf("\n");}
MPI_Type_free(&VType);MPI_Finalize();return 0;
}
$ mpirun -n 2 source
0 1 0 0 0 0 6 7 0 0 0 0 12 13 0 0 0 0 18 19 0 0 0 0.
Calcul distribué
Types de données dérivés
Extraction à pas constant : MPI_Type_vector
Le processus récepteur peut aussi réorganiser les données reçues, parexemple au début du tableau.
Il faut faire attention au nombre de données e�ectivement reçues (ici8 éléments de types MPI_INT).
// types/vector_2.celse if (wrank==1){
MPI_Recv(data, 8, MPI_INT, 0, 28, MPI_COMM_WORLD,MPI_STATUS_IGNORE);
for (int i=0; i < 8; i++)printf("%d ", data[i]);
printf(".\n");}
$ mpirun -n 2 source
0 1 6 7 12 13 18 19.
Calcul distribué
Types de données dérivés
Extraction à pas variable : MPI_Type_indexed
9 Types de données dérivésIntroductionExtraction contiguë : MPI_Type_contiguousExtraction à pas constant : MPI_Type_vectorExtraction à pas variable : MPI_Type_indexedPaddingStructure de données MPI_Type_create_struct
Calcul distribué
Types de données dérivés
Extraction à pas variable : MPI_Type_indexed
int MPI_Type_indexed(int count, const int blengths[],const int displacements[], MPI_Datatype oldtype,
MPI_Datatype *newtype);
blengths[0] blengths[1] blengths[3]
disp[0]
disp[1]
disp[2]
disp[3]
blengths[2]
count est le nombre de blocks. C'est aussi la taille de blengths etdisplacements.
Le nombre total d'éléments est la somme des éléments de blengths.
Calcul distribué
Types de données dérivés
Extraction à pas variable : MPI_Type_indexed
// types/indexed.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(&argc, &argv);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int data[24];for (int i=0; i<24; ++i)
data[i] = 0;
int blengths[] = {2, 3, 4, 2};int disp[] = {1, 7, 12, 19};
MPI_Datatype IType;MPI_Type_indexed(4, blengths, disp, MPI_INT, &IType);MPI_Type_commit(&IType);
Calcul distribué
Types de données dérivés
Extraction à pas variable : MPI_Type_indexed
if (wrank==0){
for (int i=0; i < 24; i++)data[i] = i;
MPI_Ssend(data, 1, IType, 1, 28, MPI_COMM_WORLD);}else if (wrank==1){
MPI_Recv(data, 1, IType, 0, 28, MPI_COMM_WORLD,MPI_STATUS_IGNORE);
for (int i=0; i < 24; i++)printf("%d ", data[i]);
printf("\n");}
MPI_Type_free(&IType);MPI_Finalize();return 0;
}
Calcul distribué
Types de données dérivés
Extraction à pas variable : MPI_Type_indexed
$ mpirun -n 2 source
0 1 2 0 0 0 0 7 8 9 0 0 12 13 14 15 0 0 0 19 20 0 0 0.
On peut également réorganiser les données reçues.
// types/indexed_2.celse if (wrank==1){
MPI_Recv(data, 11, MPI_INT, 0, 28, MPI_COMM_WORLD,MPI_STATUS_IGNORE);
for (int i=0; i < 11; i++)printf("%d ", data[i]);
printf(".\n");}
$ mpirun -n 2 source
1 2 7 8 9 12 13 14 15 19 20.
Calcul distribué
Types de données dérivés
Padding
9 Types de données dérivésIntroductionExtraction contiguë : MPI_Type_contiguousExtraction à pas constant : MPI_Type_vectorExtraction à pas variable : MPI_Type_indexedPaddingStructure de données MPI_Type_create_struct
Calcul distribué
Types de données dérivés
Padding
Les données doivent être alignées dans la mémoire (contraintematériel). Cela signi�e que l'adresse initiale d'une variable de typeprimitif de taille X octets doit être divisible par X .
Les champs d'une structure sont écrits en mémoire de manière àminimiser l'espace mémoire de la structure tout en respectant
l'alignement.
Il en va de même pour les cases d'un tableau.
Pour respecter l'alignement, soit dans les structures, soit dans lestableaux, des octets inutilisés sont ajoutés en mémoire. C'est lepadding.
Calcul distribué
Types de données dérivés
Padding
typedef struct{
char c;int i;short int si;
} A;
A tab[2];
0x0 0x4 0x8
tab[0] tab[1]
0xC
Disons que l'adresse de tab, et donc de tab[0].c est 0x0 (en héxadécimal)pour simpli�er.
Calcul distribué
Types de données dérivés
Padding
0x0 0x4 0x8
tab[0] tab[1]
0xC
L'adresse de tab[0].i est la première adresse divisible par 4 après0x1, soit 0x4. On a ajouté trois octets de padding.
tab[0].si peut être directement après tab[0].i puisque 0x8 estdivisible par 2. Pas de padding.
Si on plaçait tab[1] immédiatement après tab[0], tab[1].i tomberaitsur l'adresse 0xE non divisible par 4. Deux octets de padding sontajoutés à la �n de la structure.
Le résultat de sizeof(A) est 12.
Calcul distribué
Types de données dérivés
Padding
Veri�cation avec la fonction offsetof de stddef.h.
#include <stddef.h>#include <stdio.h>
typedef struct{
char c;int i;short int si;
} A;
int main(){
printf("c: %d, i: %d, si: %d, total: %d\n", offsetof(A, c),offsetof(A, i), offsetof(A, si), sizeof(A));
return 0;}
Résultat :c : 0, i : 4, si : 8, total : 12.
Calcul distribué
Types de données dérivés
Structure de données MPI_Type_create_struct
9 Types de données dérivésIntroductionExtraction contiguë : MPI_Type_contiguousExtraction à pas constant : MPI_Type_vectorExtraction à pas variable : MPI_Type_indexedPaddingStructure de données MPI_Type_create_struct
Calcul distribué
Types de données dérivés
Structure de données MPI_Type_create_struct
int MPI_Type_create_struct(int count, int *array_of_blocklengths,MPI_Aint *array_of_displacements, MPI_Datatype *array_of_types,
MPI_Datatype *newtype);
count : le nombre de champs de la structure.
array_of_blocklengths : tableau de taille count. Chaque élément dutableau est le nombre d'éléments du champ associé (1 pour les typesprimitifs, taille_du_tableau pour les tableaux).
array_of_displacements : tableau de taille count. Chaque élément dutableau est l'adresse du champ dans la structure.
array_of_types : tableau de taille count contenant les types dechaque champs.
newtype : l'adresse du type créé par la fonction.
Calcul distribué
Types de données dérivés
Structure de données MPI_Type_create_struct
La fonction offsetof de stddef.h permet de remplirarray_of_displacements.
L'exemple suivant est à compiler avec l'option −lm pour l'utilisationdu cos.
// types/create_struct.c#include <math.h>#include <mpi.h>#include <stddef.h>#include <stdio.h>
#define FIELDS 3#define TRACKS 14
typedef struct{
int track_count;double lengths[TRACKS];double total;
} album;
Calcul distribué
Types de données dérivés
Structure de données MPI_Type_create_struct
int main(int argc, char** argv){
MPI_Init(NULL, NULL);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int blocklengths[FIELDS] = {1, TRACKS, 1};
MPI_Aint displacements[FIELDS];displacements[0] = offsetof(album, track_count);displacements[1] = offsetof(album, lengths);displacements[2] = offsetof(album, total);
MPI_Datatype types[FIELDS] = {MPI_INT, MPI_DOUBLE, MPI_DOUBLE};MPI_Datatype mpi_album;
MPI_Type_create_struct(FIELDS, blocklengths, displacements,types, &mpi_album);
MPI_Type_commit(&mpi_album);
Calcul distribué
Types de données dérivés
Structure de données MPI_Type_create_struct
album silence;if (wrank==0){
silence.track_count = TRACKS;silence.total = 0;for (int i=0; i<TRACKS; ++i){
silence.lengths[i] = fabs(5*cos(i));silence.total += silence.lengths[i];
}
MPI_Ssend(&silence, 1, mpi_album, 1, 28, MPI_COMM_WORLD);}else if (wrank==1){
MPI_Recv(&silence, 1, mpi_album, 0, 28, MPI_COMM_WORLD,MPI_STATUS_IGNORE);
printf("track_count: %d\nlengths:", silence.track_count);for (int i=0; i<TRACKS; ++i)
printf(" %.2f", silence.lengths[i]);printf("\ntotal: %.2f\n", silence.total);
}
Calcul distribué
Types de données dérivés
Structure de données MPI_Type_create_struct
MPI_Type_free(&mpi_album);MPI_Finalize();return 0;
}
$ mpirun -n 2 sourcetrack_count : 14lengths : 5.00 2.70 2.08 4.95 3.27 1.42 4.80 3.77 0.73 4.56 4.20 0.02 4.22 4.54
total : 46.25
Calcul distribué
Communicateurs
10 CommunicateursPartitionner un communicateur
Calcul distribué
Communicateurs
Partitionner un communicateur
10 CommunicateursPartitionner un communicateur
Calcul distribué
Communicateurs
Partitionner un communicateur
int MPI_Comm_split(MPI_Comm comm, int color, int key,
MPI_Comm *newcomm);
Tous les processus d'une même couleur se retrouvent dans le mêmecommunicateur.
La variable newcomm a le même nom pour tous les processus, mais sadé�nition di�ère : pour le processus X , le newcomm ne contient que lesprocessus de même couleur que X .
Chaque processus a un rang dans le nouveau communicateur ;celui-ci peut di�érer du rang dans MPI_COMM_WORLD.
Les rangs du nouveau communicateur vont de 0 à #processus − 1.
L'argument key permet de contrôler les nouveaux rangs : si leprocessus X a une key inférieure à celle du processus Y (pour unemême couleur), le rang de X dans le nouveau communicateur serainférieur à celui de Y .
Calcul distribué
Communicateurs
Partitionner un communicateur
// comm_split.c#include <mpi.h>#include <stdio.h>
int main(int argc, char** argv){
MPI_Init(NULL, NULL);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int colors[4] = {11, 11, 10, 11};MPI_Comm new_comm;MPI_Comm_split(MPI_COMM_WORLD, colors[wrank], -wrank, &new_comm);
int nrank;MPI_Comm_rank(new_comm, &nrank);
int witness = 100*wrank;MPI_Bcast(&witness, 1, MPI_INT, 0, new_comm);printf("world: %d, new: %d, witness: %d\n", wrank, nrank, witness);
MPI_Finalize();return 0;
}
Calcul distribué
Communicateurs
Partitionner un communicateur
$ mpirun -n 2 sourceworld : 1, new : 1, witness : 300world : 3, new : 0, witness : 300world : 0, new : 2, witness : 300
world : 2, new : 0, witness : 200
Les processus de wrank 0, 1, 3 ont même couleur, et le processus dewrank 2 est tout seul.
L'argument key étant -wrank, les rangs dans le nouveauxcommunicateurs se retrouvent dans l'ordre inverse de MPI_WORLD_COMM.
Le broadcast ne s'e�ectue e�ectivement qu'à l'interieur du nouveaucommunicateur.
Calcul distribué
Analyse de codes MPI
11 Analyse de codes MPIDebugMéthodologie de debug de code MPIPro�lageAutres problèmes
Calcul distribué
Analyse de codes MPI
Debug
11 Analyse de codes MPIDebugMéthodologie de debug de code MPIPro�lageAutres problèmes
Calcul distribué
Analyse de codes MPI
Debug
Debugger parallèle : cher, nécessaire quand le nombre de processusdevient trop grand, adapté pour les clusters.
TotalView :http://www.roguewave.com/products-services/totalview
DDT : http://www.allinea.com/products/ddt
Debugger série : su�t pour un petit nombre de processus.gdb : https://www.open-mpi.org/faq/?category=debugging(section 6)
Calcul distribué
Analyse de codes MPI
Debug
Pour attacher gdb à un processus, il faut connaître la machine et lePID du processus.
Ne pas oublier de compiler avec l'option −g .
// debug.c#include <mpi.h>#include <stdio.h>#include <unistd.h>
int main(int argc, char** argv){
MPI_Init(&argc, &argv);int world_size;MPI_Comm_size(MPI_COMM_WORLD, &world_size);
int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
Calcul distribué
Analyse de codes MPI
Debug
int i = 0;char hostname[256];gethostname(hostname, sizeof(hostname));if (wrank==0){
printf("PID %d on %s ready for attach\n", getpid(), hostname);fflush(stdout);while (0 == i)
sleep(5);}
MPI_Barrier(MPI_COMM_WORLD);// Suite du programme.MPI_Finalize();return 0;
}
Calcul distribué
Analyse de codes MPI
Debug
$ gdb
(gdb) attach PID (stoppe l'exécution du processus)
(gdb) up (plusieurs fois, jusqu'à atteindre la fonction sleep)
(gdb) set var i = 1 (pour sortir de la boucle)
(gdb) c (pour reprendre l'exécution)
Calcul distribué
Analyse de codes MPI
Debug
Une seconde méthode permet de lancer autant de gdb que deprocessus.
Facile si tous les processus sont lancés sur localhost, plus compliquési on est sur un cluster (voir lien frame 177).
Nécessite seulement un MPI_Barrier au début du programme :notamment, pas besoin d'ajouter hostname/pid/sleep comme pourl'autre méthode.
La commande
$ mpirun -n 4 xterm -e gdb source
lancera gdb dans quatres terminaux : un par processus. Il faut lancerles programmes (avec run) dans chaque gdb.
Calcul distribué
Analyse de codes MPI
Méthodologie de debug de code MPI
11 Analyse de codes MPIDebugMéthodologie de debug de code MPIPro�lageAutres problèmes
Calcul distribué
Analyse de codes MPI
Méthodologie de debug de code MPI
Quelques recommendations.
Débugger le programme en série sans MPI (gdb / printf).
Débugger le programme MPI avec un seul processus (gdb / printf).Utiliser exclusivement des MPI_Ssend (mode synchrone) et MPI_Recv
pour les communications point-à-point (les communicationscollectives peuvent être laissées en l'état) et
véri�er les communications (MPIP / printf),éventuellement débugger avec gdb.
Changer les MPI_Ssend (mode synchrone) et MPI_Recv en d'autresmode de communications si nécessaire.
Calcul distribué
Analyse de codes MPI
Pro�lage
11 Analyse de codes MPIDebugMéthodologie de debug de code MPIPro�lage
Mesures temporelles simples
MPIP
MPE
OPro�le
Autres problèmes
Calcul distribué
Analyse de codes MPI
Pro�lage
Pro�ler consiste à analyser plusieurs aspects d'un programme(l'utilisation mémoire, le temps d'exécution des fonctions /instructions, . . .) dans le but de l'optimiser.Pro�lers commerciaux :
Intel VTune : https://software.intel.com/en-us/intel-vtune-amplifier-xe/
Allinea MAP : http://www.allinea.com/products/map
Pro�lers libres :MPIP : http://mpip.sourceforge.net/ (uniquement pour lesfonctions MPI).MPE :http://www.mcs.anl.gov/research/projects/perfvis/
(uniquement pour les fonctions MPI).OPro�le : http://oprofile.sourceforge.net/news/(indépendant de MPI).Valgrind : http://valgrind.org/ (indépendant de MPI).
Calcul distribué
Analyse de codes MPI
Pro�lage
Mesures temporelles simples
Mesure externe : la commande time
$ time mpirun -n 2 sourcereal 0m6.808s
user 0m10.172s
sys 0m0.120s
real : temps écoulé entre le début et la �n du programme. Les autresprocessus de la machine in�uent sur cette mesure.
user : temps CPU passé à l'exécution du programme en modeutilisateur. Indépendant des autres processus.
sys : temps CPU passé à l'exécution du programme en mode kernel.Indépendant des autres processus.
Calcul distribué
Analyse de codes MPI
Pro�lage
Les temps user et sys ne concernent que la machine sur laquelle lacommande time a été lancée.
La mesure externe n'est donc utile que lorsque tous les processus setrouvent sur la même machine.
Les temps user et sys rapportent la somme des temps CPU dechaque c÷ur.
Sur notre exemple, 2 c÷urs ont totalisés (10.172+ 0.120)s de tempsCPU : puisque les deux c÷urs ont travaillés en parallèle, le tempsuser+sys est supérieur au temps real.
Calcul distribué
Analyse de codes MPI
Pro�lage
Mesure interne : la fonction double MPI_Wtime()
Renvoie le nombre de secondes écoulées depuis une date passéearbitraire (qui ne change pas au cours de l'exécution).
Peut utiliser (ou non, s'il y a mieux) la fonction C gettimeofday
(man gettimeofday).
Inconvénient : nécessite de modi�er le code.
// wtime.c#include <mpi.h>#include <stdio.h>#include <unistd.h>
Calcul distribué
Analyse de codes MPI
Pro�lage
int main(int argc, char **argv){
MPI_Init(&argc, &argv);int wrank;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
int witness = 0;if (wrank==2){
int modifier = 1;sleep(2);MPI_Send(&modifier, 1, MPI_INT, 3, 28, MPI_COMM_WORLD);
}else if (wrank==3){
double start = MPI_Wtime();MPI_Recv(&witness, 1, MPI_INT, 2, 28, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);printf("MPI_Recv : %f secondes.\n", MPI_Wtime()-start);
}
Calcul distribué
Analyse de codes MPI
Pro�lage
MPI_Barrier(MPI_COMM_WORLD);printf("Rang %d, witness %d.\n", wrank, witness);MPI_Finalize();return 0;
}
$ mpirun -n 2 sourceMPI_Recv : 2.000119 secondes.Rang 3, witness 1.Rang 2, witness 0.Rang 1, witness 0.
Rang 0, witness 0.
Calcul distribué
Analyse de codes MPI
Pro�lage
MPIP
http://mpip.sourceforge.net/
Pro�le uniquement les fonctions MPI.
Ne nécessite pas de modi�cations de code.
Ne nécessite pas de recompiler le programme, mais donne desresultats plus précis si on compile en debug.
Nécessite de relinker le programme.
Nécessite libunwind (présent dans les dépôts debian).
Calcul distribué
Analyse de codes MPI
Pro�lage
$ mpicc -g -o source source.c -L${mpiP_root}/lib -lmpiP -lm -lbfd -liberty-lunwind
$ mpirun -n 4 source
Produit un �chier source.X.XXXX.X.mpiP comportant six sections :
MPI Time,
Callsites,
Aggregate Time,
Aggregate Sent Message Size,
Callsite Time statistics,
Callsite Message Sent statistics.
Les slides suivant décrivent la sortie obtenue en lançant le programme deMPI_Wtime.
Calcul distribué
Analyse de codes MPI
Pro�lage
MPI Time (seconds)
Task AppTime MPITime MPI%
0 2 2 100.00
1 2 2 100.00
2 2 0.0004 0.02
3 2 2 99.98
* 8 6 74.99
Task : le rang du processus ou * pour la somme.
AppTime : temps total du programme.
MPITime : temps passé dans les fonctions MPI uniquement.
MPI% : rapport entre MPITime et AppTime.
Calcul distribué
Analyse de codes MPI
Pro�lage
Callsites : 3
ID Lev File/Address Line Parent_Funct MPI_Call
1 0 wtime.c 26 main Barrier
2 0 wtime.c 17 main Send
3 0 wtime.c 22 main Recv
ID : identi�ant utilisé pour les autres statistiques.
Lev : ( ? :/)
File/Address : le �chier d'origine.
Line : la ligne de l'appel MPI.
Parent_Func : la fonction qui contient l'appel MPI.
MPI_Call : la fonction MPI appelée.
Calcul distribué
Analyse de codes MPI
Pro�lage
Aggregate Time (top twenty, descending, milliseconds)
Call Site Time App% MPI% COV
Barrier 1 4e+03 49.99 66.66 1.15
Recv 3 2e+03 25.00 33.34 0.00
Send 2 0.105 0.00 0.00 0.00
Call : la fonction MPI appelée.
Site : identi�ant du site (ID de la section Callsite).
Time : somme sur tous les processus du temps passé dans cettefonction MPI.
App% : le rapport entre Time et le temps total du programme.
MPI% : le rapport entre Time et le temps total MPI.
COV : coe�cient de variation entre les processus.
Calcul distribué
Analyse de codes MPI
Pro�lage
Aggregate Sent Message Size (top twenty, descending, bytes)
Call Site Count Total Avrg Sent%
Send 2 1 4 4 100.00
Call : la fonction MPI appelée.
Site : identi�ant du site (ID de la section Callsite).
Count : le nombre d'appel a la fonction.
Total : le nombre total d'octets envoyés par cette fonction.
Avrg : le nombre moyen par appel d'octets envoyés.
Sent% : le rapport entre Total et le nombre total d'octets envoyéspar toutes les fonctions MPI.
Calcul distribué
Analyse de codes MPI
Pro�lage
Callsite Time statistics (all, milliseconds) : 6
Name Site Rank Count Max Mean Min App% MPI%
Barrier 1 0 1 2e+03 2e+03 2e+03 100.00 100.00
Barrier 1 1 1 2e+03 2e+03 2e+03 100.00 100.00
Barrier 1 2 1 0.295 0.295 0.295 0.01 73.75
Barrier 1 3 1 0.031 0.031 0.031 0.00 0.00
Barrier 1 * 4 2e+03 1e+03 0.031 49.99 66.66
Recv 3 3 1 2e+03 2e+03 2e+03 99.98 100.00
Recv 3 * 1 2e+03 2e+03 2e+03 25.00 33.34
Send 2 2 1 0.105 0.105 0.105 0.01 26.25
Send 2 * 1 0.105 0.105 0.105 0.00 0.00
Calcul distribué
Analyse de codes MPI
Pro�lage
Name : la fonction MPI appelée.
Site : identi�ant du site (ID de la section Callsite).
Rank : le rang du processus.
Count : le nombre d'appel à la fonction.
Max : le temps (en millisecondes) du plus long appel à la fonction.
Mean : le temps moyen (en millisecondes) d'un appel à la fonction.
Min : le temps (en millisecondes) du plus court appel à la fonction.
App% : le rapport entre le temps passé dans cette fonction et letemps total d'exécution du programme.
MPI% : le rapport entre le temps passé dans cette fonction et letemps total d'exécution des fonctions MPI.
Calcul distribué
Analyse de codes MPI
Pro�lage
Callsite Message Sent statistics (all, sent bytes)
Name Site Rank Count Max Mean Min Sum
Send 2 2 1 4 4 4 4
Send 2 * 1 4 4 4 4
Name : la fonction MPI appelée.
Site : identi�ant du site (ID de la section Callsite).
Rank : le rang du processus.
Count : le nombre d'appel à la fonction.
Max : le plus grand nombre d'octets transférés en un appel.
Mean : le nombre moyen par appel d'octets transférés.
Min : le plus petit nombre d'octets transférés en un appel.
Sum : la somme des octets transférés pour tous les appels de lafonctions.
Calcul distribué
Analyse de codes MPI
Pro�lage
MPE
http://www.mcs.anl.gov/research/projects/perfvis/
Pro�le uniquement les fonctions MPI.
Ne nécessite pas de modi�cations de code.
Ne nécessite pas de recompiler le programme.
Nécessite de relinker le programme.
Viens avec une interface graphique.
Ne marche pas avec du C++.
Calcul distribué
Analyse de codes MPI
Pro�lage
$ mpicc -c source.c -o source.o$ mpecc -mpilog source.o -o source
$ mpirun -n 4 source
Produit un �chier source.clog2.L'interface graphique, assez intuitive, se lance avec :$ jumpshot source.clog2
Calcul distribué
Analyse de codes MPI
Pro�lage
OPro�le
http://oprofile.sourceforge.net/news/
Permet de compter les cycles CPU, les 'cache misses' (et un tasd'autres paramètres) de chaque fonctions / instructions d'unprogramme.
Ne nécessite pas de modi�cations de code.
Nécessite de recompiler le programme en debug pour avoir desinformations précises.
Non spéci�que au programme MPI.
Documentation : http://oprofile.sourceforge.net/docs/
Ne marche pas dans les machines virtuelles.
Calcul distribué
Analyse de codes MPI
Pro�lage
Quick start (cycles CPU) :
$ operf -t mpirun -n 2 source$ opreport -l -m tid source -o pro�le
$ opannotate -as -t 2 source > annotated
operf permet d'analyser le programme. Les resultats sont écrits dansle dossier oprofile_data. L'option -t permet de séparer les di�érentsprocessus.
La ligne opreport génère le �chier pro�le qui contient, pour chaquefonctions appelées et pour chaque processus, le nombre de cycleCPU passés dans cette fonction.
La ligne opannotate génère le �chier annotated qui contient lesinstructions assembleurs du code, et pour chacune d'elle, le nombrede cycle CPU passés dans cette instruction.
Calcul distribué
Analyse de codes MPI
Pro�lage
Le �chier pro�le s'organise de la manière suivante :
samples % samples % image name symbol name33038 39.6791 32711 39.2963 source ma_fonction(int, int)
Les deux premières colonnes réfèrent au processus de rang 0, avec lenombre et le pourcentage de cycles passés dans la fonctionma_fonction.
Les 3ième et 4ième colonnes réfèrent au processus de rang 1.
Les 5ième et 6ième colonnes sont le nom de l'exécutable et leprototype de la fonction.
Calcul distribué
Analyse de codes MPI
Pro�lage
Le �chier annotated s'organise de la manière suivante :
: instruction (en C);111 0.1333 123 0.1478 : 444a8f: movslq %edx,%rdx63 0.0757 60 0.0721 : 444a92: movsd (%r8,%rdx,8),%xmm094 0.1129 73 0.0877 : 444a98: mulsd (%r11,%rax,8),%xmm0
1437 1.7259 1428 1.7155 : 444a9e: addsd (%rcx),%xmm0660 0.7927 675 0.8109 : 444aa2: movsd %xmm0,(%rcx)
Pour chaque instruction C, la liste des instructions assembleur estdétaillée.
On retrouve la même organisation que dans pro�le pour les 4premières colonnes.
On peut ainsi voir immédiatement les passages lents du code, mais laméthode n'est pas parfaite :http://oprofile.sourceforge.net/doc/debug-info.html.
Calcul distribué
Analyse de codes MPI
Pro�lage
On peut demander à operf de mesurer d'autres paramètres avecl'option -e.
La liste de ces paramètres dépend de l'architecture dumicroprocesseur : http://oprofile.sourceforge.net/docs/.
LLC_MISSES en particulier peut être intéressant à analyser /optimiser.
Calcul distribué
Analyse de codes MPI
Autres problèmes
11 Analyse de codes MPIDebugMéthodologie de debug de code MPIPro�lageAutres problèmes
Opérations �otantes
Race condition
Calcul distribué
Analyse de codes MPI
Autres problèmes
Opérations �otantes
Les opérations sur les �otants ne sont pas associatives : le résultatdépend de l'ordre des opérations.
Dans les codes parallèles, l'ordre des opérations à e�ectuer peutdépendre du nombre de processus utilisés.
Le code série et les codes parallèles pourront donc donner desrésultats di�érents, et on peut se poser la question
La di�érence est-elle dû à une erreur dans le code parallèleou aux erreurs d'arrondis ?
Très di�cile de répondre en général. Il existe une méthode decorrection d'erreurs (assez lourde).
Calcul distribué
Analyse de codes MPI
Autres problèmes
// roundoff.c#include <mpi.h>#include <stdio.h>#include <stdlib.h>
#define TE 28000
int main(int argc, char** argv){
MPI_Init(&argc, &argv);int wrank, world_size;MPI_Comm_rank(MPI_COMM_WORLD, &wrank);MPI_Comm_size(MPI_COMM_WORLD, &world_size);
float tab[TE];if (wrank==0){
for (int i=0; i<TE; ++i)tab[i] = (rand() % 1000) / 1000.;
}
MPI_Bcast(tab, TE, MPI_FLOAT, 0, MPI_COMM_WORLD);
Calcul distribué
Analyse de codes MPI
Autres problèmes
float local = 0;for (int i=wrank; i<TE; i+=world_size)
local += tab[i];
float result;MPI_Reduce(&local, &result, 1, MPI_FLOAT, MPI_SUM, 0,
MPI_COMM_WORLD);
if (wrank==0){
float serial = 0;for (int i=0; i<TE; ++i)
serial += tab[i];
printf("serial: %f, parallel: %f\n", serial, result);}
MPI_Finalize();return 0;
}
Calcul distribué
Analyse de codes MPI
Autres problèmes
$ mpirun -n 2 sourceserial : 13911.528320, parallel : 13911.541016
$ mpirun -n 4 sourceserial : 13911.528320, parallel : 13911.516602
$ mpirun -n 8 sourceserial : 13911.528320, parallel : 13911.522461
Calcul distribué
Analyse de codes MPI
Autres problèmes
Race condition
On est en situation de 'race condition' lorsque le résultat duprogramme dépend de l'ordre d'exécution des instructions desdi�érents processus.
Ne peut se produire que si une resource commune à plusieursprocessus (pour MPI, le disque dur) est modi�ée/lue.
Peut être réglé en ajoutant des synchronisations.
Voir l'exemple frame 60.
top related