Introduction à LAM

1. Gestion de l'environnement

Le sous-programme MPI_INIT initialise l'environnement nécessaire et MPI_FINALIZE désactive cet environnement. Les opérations effectuées par MPI portent sur des communicateurs, c'est-à-dire un groupe de processus, chacun possédant un rang, et un contexte de communication, soit un objet gérant les échanges point à point et collectif à l'aide d'étiquettes (tag) au sein de ce groupe. Les messages sont toujours reçus dans le contexte d'où ils sont émis et les messages envoyés dans différents contextes n'interfèrent pas.

Le communicateur par défaut est MPI_COMM_WORLD, il comprend l'ensemble des processus actifs. Le nombre de processus gérés par un communicateur est fourni par le sous-programme MPI_COMM_SIZE. De même, le sous-programme MPI_COMM_RANK retourne le rang d'un processus (valeur comprise entre 0 et celle renvoyée par MPI_COMM_SIZE -1).

Un peu de vocabulaire :

Il existe différents modes de communication avec MPI :

2. Fonctionnement de LAM

LAM se présente comme un simple démon présent sur chacune des machines. Chaque démon est structuré comme un micronoyau fournissant des services de passage de messages et de synchronisation. Certain processus internes au démon forment un sous-système de communication qui permet le passage de messages vers les démons des autres machines. La communication entre les différents processus se fait via UDP c'est à dire en mode non connecté et par paquets.

La communication se fait point à point : un message va d'un processus vers un autre sans nécessairement passer par le serveur. Les programmes écrits pour LAM sont compatibles avec les autres implémentations de MPI. LAM détecte les erreurs de communication dues à un « crash » d'une machine ou à une rupture de communication. LAM bloque toutes les communications vers la machine posant problème, les processus restants sont informés de la panne de manière asynchrone.

On peut donc gérer ce type d'erreurs dans lesapplications en supprimant les communications vers les processus ne réagissant plus et en créant de nouveaux.

2.1. Communications point à point

Une communication point à point a lieu entre deux processus, l'un est appelé émetteur, l'autre récepteur, identifiés par leur rang. Il s'agit de la communication de base de MPI et les opérations effectuées sont un send et un receive.Il existe différentes manières d'effectuer la communication. De manière générale, les paramètres nécessaires à sa construction sont :

Un code de retour fait partie des arguments, sa valeur (si différente de zéro) indique le type de problème rencontré.

2.1.a) Communications bloquantes :

Un envoi est bloquant signifie qu'il ne termine son action que lorsque les données envoyées ont été reçues et stockées par le destinataire de telle sorte que l'expéditeur peut accéder et modifier les valeurs en envoi.

La syntaxe d'un envoi bloquant standard est la suivante :

MPI_SEND(don, taille, dtype, dest, tag, comm, irc)
<dtype>don(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER irc (OUT) code de retour.

Il s'agit de l'envoi d'un message identifié tag, de taille taille, de type dtype, à partir de l'adresse on, au processus dest, dans le communicateur comm. La longueur du message est spécifiée en nombre d'éléments plutôt qu'en octets. Seul le code de retour est modifié par l'appel (il est en sortie, soit OUT).

Les trois derniers arguments (sans compter le code de retour) constituent l'enveloppe du message. Le destinataire est dest, un entier dont la valeur est comprise entre 0 et le nombre de processus -1. L'étiquette tag est un entier compris entre 0 et 32767 (au minimum) ; il permet de distinguer les types de messages. L'argument comm indique le communicateur utilisé pour l'envoi du message.

La syntaxe d'un envoi bloquant synchronous est la suivante :

MPI_SSEND(don, taille, dtype, dest, tag, comm, irc)
<dtype> don(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER irc (OUT) code de retour.

Un envoi bloquant en mode buffered s'écrit :

MPI_BSEND (don, taille, dtype, dest, tag, comm, irc)
<dtype> don(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER irc (OUT) code de retour.

Enfin, l'envoi bloquant en mode ready s'écrit :

MPI_RSEND (don, taille, dtype, dest, tag, comm, irc)
<dtype> don(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER irc (OUT) code de retour.

La réception bloquante est faite de la manière suivante :

MPI_RECV (don, taille, dtype, source, tag, comm, status, irc)
<dtype> don(*) (OUT) donnée (adresse initiale) à recevoir,
INTEGER taille (IN) nombre d'éléments à recevoir,
INTEGER dtype (IN) type MPI de chaque élément à recevoir,
INTEGER source (IN) rang du processus expéditeur,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER status (MPI_STATUS_SIZE) (OUT) informations sur la réception,
INTEGER irc (OUT) code de retour.

Il s'agit de la réception d'un message identifié tag, de taille taille, de type dtype, placé à partir de l'adresse don, du processus source, dans le communicateur comm. L'argument supplémentaire status contient des informations sur la réception. Les constantes MPI_SOURCE, MPI_TAG et MPI_ERROR sont les indices de stockage dans status des champs source, étiquette et code d'erreur du message reçu.

Il n'y a qu'une opération de réception qui peut être associée avec les quatre opérations d'envoi. Elle est bloquante et ne rend la main que lorsque la donnée est reçue.

Exemple :
    PROGRAM send_recv
    include 'mpif.h'
    INTEGER mon_rang
    INTEGER irc
    INTEGER tag
    INTEGER status (MPI_STATUS_SIZE)
    REAL valeur
  ! Initialisation
    CALL MPI_INIT (irc)
    CALL MPI_COMM_RANK (MPI_COMM_WORLD, mon_rang, irc)
    tag = 100
  ! Envoi
    IF (mon_rang .EQ. 0) THEN
        valeur = 10.0
        CALL MPI_SEND (valeur, 1, MPI_REAL, 1, tag, MPI_COMM_WORLD, irc)
  ! Réception
    ELSE
        valeur = 0.0
        CALL MPI_RECV (valeur, 1, MPI_REAL, 0, tag, MPI_COMM_WORLD, status, irc)
        WRITE (6, *) 'Processus rang ', mon_rang, ' a recu la valeur ', valeur
    ENDIF
  ! Sortie
    CALL MPI_FINALIZE (irc)
    STOP
    END

La sélection d'un message dans une opération de réception est réalisée à l'aide du contenu de l'enveloppe du message. Un message peut être reçu par une opération de réception si son enveloppe correspond aux arguments source, tag et comm spécifiés dans l'opération de réception. Le destinataire peut spécifier comme source MPI_ANY_SOURCE et/ou comme étiquette MPI_ANY_TAG pour indiquer que n'importe quelle source et étiquette sont acceptées. Le communicateur doit être le même que pour l'envoi. Ainsi, un envoi doit spécifier son destinataire mais une réception peut accepter des messages d'un émetteur arbitraire.

L'échange des données entre deux processus permet d'effectuer une opération d'envoi et une opération de réception en une seule fois. Les deux processus peuvent être les mêmes. Cette opération est réalisée par MPI_SENDRECV. Dans le cas de send et receive bloquants, il faut faire attention à l'ordre des opérations pour éviter les deadlock, c'est-à-dire (par exemple) que tous les processus sont en même temps en attente de réception.

MPI_SENDRECV (senddon, sendtaille, sendtype, dest, sendtag, recvdon, recvtaille, recvtype, source, recvtag, comm, status, irc)
<sendtype> senddon(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER sendtaille (IN) nombre d'éléments à envoyer,
INTEGER sendtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER sendtag (IN) étiquette de l'envoi,
<recvtype> recvdon(*) (OUT) donnée (adresse initiale) à recevoir,
INTEGER recvtaille (IN) nombre d'éléments à recevoir,
INTEGER source (IN) rang du processus expéditeur,
INTEGER recvtag (IN) étiquette de la réception,
INTEGER comm (IN) communicateur,
INTEGER status (MPI_STATUS_SIZE) (OUT) informations sur la réception,
INTEGER irc (OUT) code de retour.

Il s'agit d'un envoi et d'une réception bloquants. Ces deux opérations utilisent le même communicateur, mais des étiquettes pouvant être différentes. Les données à envoyer et recevoir doivent être disjointes mais peuvent avoir des types et des longueurs différentes. On peut aussi permuter des valeurs entre deux processus, à l'aide du MPI_SENDRECV_REPLACE.

MPI_SENDRECV_REPLACE (don, taille, type, dest, sendtag, source, recvtag, comm, status, irc)
<sendtype> don(*) (INOUT) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER type (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER sendtag (IN) étiquette de l'envoi,
INTEGER source (IN) rang du processus expéditeur,
INTEGER recvtag (IN) étiquette de la réception,
INTEGER comm (IN) communicateur,
INTEGER status (MPI_STATUS_SIZE) (OUT) informations sur la réception,
INTEGER irc (OUT) code de retour.

Il s'agit d'un envoi et d'une réception bloquants. La même donnée est utilisée pour l'envoi et la réception de telle sorte que le message envoyé est remplacé par le message reçu.

2.1.b) Communications non bloquantes :

On peut augmenter les performances en faisant un recouvrement des communications par des calculs. On utilise pour cela des communications non bloquantes. Un send non bloquant initialise l'opération d'envoi mais ne la réalise pas. L'appel au sous-programme sera fini avant que le message ne soit parti. Une opération de vérification ultérieure est nécessaire pour s'assurer de la fin de l'envoi. Le transfert des données à partir de la mémoire de l'expéditeur peut être fait simultanément avec des calculs, après l'initialisation de l'envoi et avant sa complétion.

Il en est de même pour une réception non bloquante. Un receive non bloquant initialise l'opération de réception mais ne la réalise pas. L'appel au sous-programme sera fini avant que le message ne soit reçu. Une opération de vérification ultérieure est nécessaire pour s'assurer de la réception effective du message. Le transfert des données vers la mémoire du destinataire peut être fait simultanément avec des calculs, après que la réception soit initialisée et avant sa complétion.

Les communications non bloquantes nécessitent un argument supplémentaire appelé request, qui permet d'identifier les opérations de communication et de faire correspondre l'opération qui initialise la communication avec elle qui la réalise effectivement. Un objet request contient différentes informations concernant l'opération de communication : le mode d'envoi, le contexte, l'étiquette, les arguments de destination pour un send, ou d'expédition pour un receive.

MPI_ISEND (don, taille, dtype, dest, tag, comm, request, irc)
<dtype> don(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER request (OUT) identifiant de l'envoi,
INTEGER irc (OUT) code de retour.

Les envois non bloquants utilisent les mêmes quatre modes que les envois bloquants et ont le même sens. Dans tous les cas, l'initialisation de l'envoi est locale, le sous-programme rend immédiatement la main. Enfin un envoi non bloquant peut être mis en correspondance avec une réception bloquante et vice-versa.

La syntaxe d'un envoi non bloquant standard est la suivante :

MPI_ISEND (don, taille, dtype, dest, tag, comm, request, irc)
<dtype> don(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER request (OUT) identifiant de l'envoi,
INTEGER irc (OUT) code de retour.

La syntaxe d'un envoi non bloquant synchronous est la suivante :

MPI_ISSEND (don, taille, dtype, dest, tag, comm, request, irc)
<dtype> don(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER request (OUT) identifiant de l'envoi,
INTEGER irc (OUT) code de retour.

Un envoi non bloquant en mode buffered s'écrit :

MPI_IBSEND (don, taille, dtype, dest, tag, comm, request, irc)
<dtype> don(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER request (OUT) identifiant de l'envoi,
INTEGER irc (OUT) code de retour.

Enfin, l'envoi non bloquant en mode ready s'écrit :

MPI_IRSEND (don, taille, dtype, dest, tag, comm, request, irc)
<dtype> don(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER request (OUT) identifiant de l'envoi,
INTEGER irc (OUT) code de retour.

La réception non bloquante est faite de la manière suivante :

MPI_IRECV (don, taille, dtype, source, tag, comm, request, irc)
<dtype> don(*) (OUT) donnée (adresse initiale) à recevoir,
INTEGER taille (IN) nombre d'éléments à recevoir,
INTEGER dtype (IN) type MPI de chaque élément à recevoir,
INTEGER source (IN) rang du processus expéditeur,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER request (OUT) identifiant de la réception,
INTEGER irc (OUT) code de retour.

Un appel non bloquant génère un objet associé à la communication, request, qui peut être utilisé pour connaître le statut d'une communication (envoi ou réception) ou permettre d'attendre sa complétion. Pour cela on utilise respectivement les routines MPI_TEST et MPI_WAIT.

MPI_TEST (request, flag, status)
INTEGER request (INOUT) objet associé à la communication
LOGICAL flag (OUT) .TRUE. si la communication est effectuée
INTEGER status(MPI_STATUS_SIZE) (OUT) informations sur la communication

Un appel à MPI_TEST renvoie flag = .TRUE. si l'opération identifiée par request est achevée. Les valeurs en sortie des arguments request et status sont alors non définies. Dans le cas contraire, l'appel renvoie flag = .FALSE. . Dans ce dernier cas, la valeur de l'objet status est non définie. Cette fonction est locale.

MPI_WAIT(request, status)
INTEGER request (INOUT) objet associé à la communication,
INTEGER status (MPI_STATUS_SIZE) (OUT) informations sur la communication.

Un appel à MPI_WAIT ne rend la main que lorsque l'opération identifiée par request est achevée. Cette fonction est non locale. Elle entraîne la désallocation de l'objet request. Un objet peut aussi être libéré sans pour autant devoir attendre la complétion de la communication associée :

MPI_REQUEST_FREE (request)
INTEGER request (INOUT) objet associé à la communication.

Si la communication est en cours, l'objet ne sera désalloué qu'après complétion.

2.1.c) Communications persistantes :

Il arrive parfois que l'on effectue une même communication un grand nombre de fois avec les mêmes arguments (même si les valeurs sont différentes), par exemple dans une boucle pour faire des mises à jour en fin d'itération. Dans un tel cas, il est possible d'optimiser la communication en associant ses arguments à un objet request persistant (initialisation) puis en utilisant cet objet request pour effectuer les communications. Cette construction permet de réduire l'overhead à chaque échange. Le requestassocié à la communication persistante est crée à l'aide d'une des quatre routines suivantes.

Création du request pour une communication persistante en mode standard :

MPI_SEND_INIT (don, taille, dtype, dest, tag, comm, request, irc)
<dtype> don(*) (IN) donnée (adresse initiale) à envoyer, INTEGER taille (IN) nombre d'éléments à envoyer, INTEGER dtype (IN) type MPI de chaque élément à envoyer, INTEGER dest (IN) rang du processus destinataire, INTEGER tag (IN) étiquette du message, INTEGER comm (IN) communicateur, INTEGER request (OUT) identifiant de la communication, INTEGER irc (OUT) code de retour.

Création du request pour une communication persistante en mode buffered :

MPI_BSEND_INIT (don, taille, dtype, dest, tag, comm, request, irc)
<dtype> don(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER request (OUT) identifiant de la communication,
INTEGER irc (OUT) code de retour.

Création du request pour une communication persistante en mode synchronous :

MPI_SSEND_INIT (don, taille, dtype, dest, tag, comm, request, irc)
<dtype> don(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER request (OUT) identifiant de la communication,
INTEGER irc (OUT) code de retour.

Création du request pour une communication persistante en mode ready :

MPI_RSEND_INIT (don, taille, dtype, dest, tag, comm, request, irc)
<dtype> don(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER dest (IN) rang du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER request (OUT) identifiant de la communication,
INTEGER irc (OUT) code de retour.

La réception persistante est initialisée par :

MPI_RECV_INIT (don, taille, dtype, source, tag, comm, request, irc)
<dtype> don(*) (OUT) donnée (adresse initiale) à recevoir,
INTEGER taille (IN) nombre d'éléments à recevoir,
INTEGER dtype (IN) type MPI de chaque élément à recevoir,
INTEGER source (IN) rang du processus expéditeur,
INTEGER tag (IN) étiquette du message,
INTEGER comm (IN) communicateur,
INTEGER request (OUT) identifiant de la réception,
INTEGER irc (OUT) code de retour.

Le premier argument, don, est mis en sortie pour spécifier le droit d'écriture sur les données à recevoir. Ces appels n'engendrent pas de communication. Une communication persistante (envoi ou réception) qui utilise un request persistant est amorcée par la subroutine MPI_START :

MPI_START (request)
INTEGER request (INOUT) identifiant de la communication

L'argument request est construit par un des cinq appels précédents et doit être inactif (c'est-à-dire inutilisé). Il devient actif une fois l'appel effectué. Cet appel est local avec des caractéristiques analogues à celles d'une communication non bloquante. Par exemple, un appel à MPI_START avec un request crée par MPI_SEND_INIT effectue la communication de la même manière qu'un appel à MPI_ISEND.

2.2. Communications collectives

Une communication collective est une communication impliquant un groupe de processus et réaliser ainsi en une fois une série de communications point à point avec possibilité d'effectuer une opération sur les données. Ces opérations se font au sein de communicateurs et n'ont pas besoin d'étiquette (tag). On peut classer les communications collectives en plusieurs catégories : synchronisation, transferts de données, transferts et opérations sur les données.

2.2.a) Synchronisation :

La routine MPI_BARRIER bloque le processus appelant jusqu'à ce que tous les membres du groupe aient fait de même. Ensuite il rend la main.

MPI_BARRIER (comm)
INTEGER comm (IN) communicateur

2.2.b) Transferts :

Il existe différents types de transferts, selon le nombre de processus émetteurs, récepteurs. Le diagramme suivant présente schématiquement les communications collectives :


MPI_BCAST (don, taille, dtype, source, comm, irc)
<dtype> don(*) (INOUT) donnée (adresse initiale) à envoyer
INTEGER taille (IN) nombre d'éléments à envoyer,
INTEGER dtype (IN) type MPI de chaque élément à envoyer,
INTEGER source (IN) rang du processus émetteur,
INTEGER comm (IN) communicateur,
INTEGER irc (OUT) code de retour.

MPI_BCAST diffuse un message du processus source vers tous les processus du groupe, lui compris. Cet appel est effectué par tous les processus utilisant les mêmes arguments pour source et comm.

MPI_GATHER (senddon, sendtaille, sendtype, recvdon, recvtaille, recvtype, source, comm, irc)
<sendtype> senddon(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER sendtaille (IN) nombre d'éléments à envoyer,
INTEGER sendtype (IN) type MPI de chaque élément à envoyer,
<recvtype> recvdon(*) (OUT) donnée (adresse initiale) à recevoir,
INTEGER recvtaille (IN) nombre d'éléments à recevoir,
INTEGER recvtype (IN) type MPI de chaque élément à recevoir,
INTEGER source (IN) rang du processus destinataire,
INTEGER comm (IN) communicateur,
INTEGER irc (OUT) code de retour.

Dans un appel à MPI_GATHER, chaque processus (source inclus) envoie ses données au processus source qui les reçoit et les stocke dans l'ordre des rangs des processus. L'adresse de stockage de la réception est ignorée par tous les processus différents de source. Les arguments sendtaille et sendtype de tout processus émetteur doivent correspondre respectivement aux arguments recvtaille et recvtype du processus source. De plus les arguments source et comm doivent être les mêmes pour tous les processus.

La routine MPI_SCATTER effectue l'opération inverse de MPI_GATHER : le processus source distribue ses données par bloc entre les processus du groupe : le i-ème processus reçoit le i-ème bloc.

MPI_SCATTER (senddon, sendtaille, sendtype, recvdon, recvtaille, recvtype, source, comm, irc)
<sendtype> senddon(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER sendtaille (IN) nombre d'éléments à envoyer,
INTEGER sendtype (IN) type MPI de chaque élément à envoyer,
<recvtype> recvdon(*) (OUT) donnée (adresse initiale) à recevoir,
INTEGER recvtaille (IN) nombre d'éléments à recevoir,
INTEGER recvtype (IN) type MPI de chaque élément à recevoir,
INTEGER source (IN) rang du processus expéditeur,
INTEGER comm (IN) communicateur,
INTEGER irc (OUT) code de retour.

Les arguments sendtaille et sendtype du processus émetteur doivent correspondre respectivement aux arguments recvtaille et recvtype de tout processus récepteur. De plus les arguments source et comm doivent être les mêmes pour tous les processus.

MPI_ALLGATHER collecte des données réparties sur tous les processus et les leur diffusent ensuite. C'est un MPI_GATHER où tous les processus sont destinataires.

MPI_ALLGATHER (senddon, sendtaille, sendtype, recvdon, recvtaille, recvtype, comm, irc)
<sendtype> senddon(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER sendtaille (IN) nombre d'éléments à envoyer,
INTEGER sendtype (IN) type MPI de chaque élément à envoyer,
<recvtype> recvdon(*) (OUT) donnée (adresse initiale) à recevoir,
INTEGER recvtaille (IN) nombre d'éléments à recevoir,
INTEGER recvtype (IN) type MPI de chaque élément à recevoir,
INTEGER comm (IN) communicateur,
INTEGER irc (OUT) code de retour.

Les arguments sendtaille et sendtype d'un processus doivent correspondre aux arguments recvtaille et recvtype de tout autre processus.

Enfin, il est possible de faire des échanges croisés entre tous les processus à l'aide du MPI_ALLTOALL. C'est en quelque sorte une extension du MPI_ALLGATHER où chaque processus envoie des données distinctes à chacun des destinataires : le j-ème bloc envoyé par le processus i est reçu par le processus j comme le i-ème bloc dans recvdon. Les arguments sendtaille et sendtype d'un processus doivent correspondre aux arguments recvtaille et recvtype de tout autre processus. MPI_ALLTOALL (senddon, sendtaille, sendtype, recvdon, recvtaille, recvtype, comm, irc)

<sendtype> senddon(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER sendtaille (IN) nombre d'éléments à envoyer,
INTEGER sendtype (IN) type MPI de chaque élément à envoyer,
<recvtype> recvdon(*) (OUT) donnée (adresse initiale) à recevoir,
INTEGER recvtaille (IN) nombre d'éléments à recevoir,
INTEGER recvtype (IN) type MPI de chaque élément à recevoir,
INTEGER comm (IN) communicateur,
INTEGER irc (OUT) code de retour.

Ces communications collectives ont des analogues (MPI_GATHERV, MPI_SCATTERV, MPI_ALLGATHERV, MPI_ALLTOALLV) pour travailler avec des données dont le nombre n'est pas le même pour tous les processus.

2.2.c) Réduction :

Une opération de réduction consiste à appliquer une même opération à un ensemble de valeurs réparties sur les processus pour en extraire une valeur unique qui sera envoyé à un (MPI_REDUCE) ou tous les processus (MPI_ALLREDUCE). Les opérations de réduction prédéfinis sont : somme, produit, maximum, minimum, indice du maximum, indice du minimum, etc ...

MPI_REDUCE (senddon, recvdon, taille, dtype, oper, dest, comm, irc)
<sendtype> senddon (*) (IN) donnée à réduire (adresse initiale),
<recvtype> recvdon (*) (OUT) résultat (adresse initiale),
INTEGER taille (IN) nombre d'éléments à recevoir,
INTEGER dtype (IN) type MPI de chaque élément à recevoir,
INTEGER oper (IN) opération de réduction,
INTEGER dest (IN) rang du processus destinataire,
INTEGER comm (IN) communicateur,
INTEGER irc (OUT) code de retour.

MPI_REDUCE combine les éléments figurant dans senddon de chaque processus du groupe à l'aide de l'opération de réduction oper et met le résultat dans recvdon du processus dest. Les données à réduire sont caractérisées par les arguments senddon, taille et dtype. Le résultat est caractérisé par les arguments recvdon, taille et dtype. Les deux ont donc le même nombre d'éléments de même type. L'appel est effectué par tous les membres du groupe et ont les mêmes arguments taille, dtype, oper, dest, comm. Dans le cas où chaque processus fournirait plus d'un élément, l'opération est d'abord effectuée sur cet ensemble.
L'opération oper est toujours supposée associative, les opérations prédéfinies sont aussi commutatives. Le type de données doit être compatible avec l'opération effectuée.

Le développeur peut construire ses propres opérations de réduction.

Ce tableau présente la liste des opérations de réduction prédéfinie :

Nom Définition
MPI_MAX maximum
MPI_MIN minimum
MPI_SUM somme
MPI_PROD produit
MPI_LAND .AND. logique
MPI_BAND .AND. bit à bit
MPI_LOR .OR. logique
MPI_BOR .OR. bit à bit
MPI_LXOR .XOR. logique
MPI_BXOR .XOR. bit à bit
MPI_MAXLOC maximum et indice
MPI_MINLOC minimum et indice
Exemple :
    PROGRAM reduce
    include 'mpif.h'
    INTEGER mon_rang
    INTEGER irc
    INTEGER tag
    INTEGER status (MPI_STATUS_SIZE)
    REAL valeur, somme
  ! Initialisation
    CALL MPI_INIT (irc)
    CALL MPI_COMM_RANK (MPI_COMM_WORLD, mon_rang, irc)
  ! Valeurs
    IF (mon_rang .EQ. 0) THEN
        valeur = 1000.0
    ELSE
        valeur = REAL (mon_rang)
    ENDIF
  ! Réduction
    CALL MPI_REDUCE (valeur, somme, 1, MPI_REAL, MPI_SUM, 0, MPI_COMM_WORLD, irc)
  ! Sortie
    IF (mon_rang .EQ. 0) WRITE (6,*) 'Somme globale : ', somme
    CALL MPI_FINALIZE (irc)
    STOP
    END