Parallel Virtual Machine
Description de la bibliothèque d'échanges de messages PVM
Introduction
Gestion de l'environnement
Communications
Gestion des groupes de processus
Introduction
PVM (Parallel Virtual Machine) a pour but de faciliter l'écriture d'applications parallèles sur un réseau de stations de travail hétérogènes (modèle MPMD : Multiple Program Multiple Data). L'utilisateur définit un ensemble de machines qui sera vu comme une seule grande machine multiprocesseur à mémoire distribuée. Le terme machine parallèle fait référence à cette machine multiprocesseurs alors que le terme hôte se réfère à l'une des machines membres de l'ensemble. Cette approche permet le regroupement d'hôtes ayant des caractéristiques différentes (machine vectorielle, station graphique, station de travail, cluster, robot de stockage, etc ...). Les communications entre les hôtes se font avec PVM qui prend en charge les conversions de formats nécessaires entre deux machines n'ayant pas les mêmes représentations internes des données. PVM est également conçue pour pouvoir fonctionner avec différents types de réseaux.Le site netlib est un site où l'on peut récupérer la distribution PVM ainsi qu'un manuel on-line (décrivant les fonctions PVM) ou sa version postscript , de même ce lien est la home page de PVM développée par Oak Ridge National Laboratory (ORNL).
Gestion de l'environnement
PVM réalise toutes ses fonctions grâce à des démons qu'il installe, lorsqu'il démarre sur chaque hôte. Ces démons gèreront tout ce qui est communication entre les hôtes. Avant toute exécution d'un programme PVM il faut donc définir l'ensemble des machines hôtes et démarrer PVM. Une fois cette opération effectuée, on peut lancer un programme PVM. Sur le cluster IBM, il suffit de placer un fichier .rhosts dans son $HOME_DIR contenant la ligne suivante :L'environnement est géré à l'aide d'options au travers de la console PVM, pvm, sur la machine hôte. En voici quelques-unes :localhost login
Un utilisateur n'a qu'un seul démon PVM, même si plusieurs applications parallèles s'exécutent en simultané, par conséquent il faut faire attention avant d'arrêter le démon. Il est possible d'insérer ces commandes dans un fichier de soumission, par exemple pour lancer le démon PVM la syntaxe est :pvm help : les différentes options
pvm quit : lancement du démon PVM et sortie de la console
pvm halt : arrêt du démon PVM
Le sous-programme PVMFMYTID permet d'intégrer le processus appelant dans l'environnement PVM,echo quit | pvm
PVMFMYTID (mytid)INTEGER mytid (OUT) identificateur (au sens UNIX) du processus.
La sortie est réalisée par PVMFEXIT :
PVMFEXIT (irc)INTEGER irc (OUT) code de retour.
Un processus PVM quelconque peut engendrer ("spawner") d'autres processus (appelés processus "fils") sur la machine parallèle en appelant le sous-programme PVMFSPAWN :
PVMFSPAWN (task, flag, where, ntask, irc)CHARACTER(*) task (IN) nom de l'exécutable et chemin absolu,
INTEGER flag (IN) spécification de la machine cible,
CHARACTER(*) where (IN) nom de la machine cible,
INTEGER ntask (IN) nombre de processus activés et dimension du tableau suivant,
INTEGER tids(*) (OUT) identificateurs des processus activés,
INTEGER irc (OUT) code de retour.
Les valeurs des arguments flag et where sont données par le tableau suivant :
| flag | where |
| PVMTASKDEFAULT | '*' |
| PVMTASKHOST | nom de la machine |
| PVMTASKARCH | nom de l'architecture |
Enfin, les processus "fils" peuvent connaitre l'identificateur du processus "père" qui les a générés à l'aide du sous-programme PVMFPARENT :
Si le processus appelant ce sous-programme n'a pas de processus père, tid vaut alors PVMNOPARENT.PVMFPARENT (tid)INTEGER tid (OUT) identificateur du processus père
Exemple :
PROGRAM identificationC Initialisationinclude 'fpvm3.h'
INTEGER mytid, tid
INTEGER itids (4)
INTEGER irc
CALL PVMFMYTID (mytid)C Nombre de processusCALL PVMFPARENT (tid)C TestIF ( tid .EQ. PVMNOPARENT ) THENC SortieWRITE (6, *) 'Je n'ai pas de processus père'
CALL PVMFSPAWN ('identification', PVMTASKDEFAULT, '*', 4, itids, irc)
ELSE
WRITE (6, *) 'Mon tid est : ', mytid, ', celui de mon processus pere est : ', tid
ENDIF
CALL PVMFEXIT (irc)STOP
END
Communications
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 :- les rangs des processus émetteur et récepteur,
- l'étiquette du message,
- le type des données échangées,
- les données.
L'envoi d'un message se fait en trois étapes. En premier, une mémoire tampon (buffer), doit être initialisée par un appel à la routine PVMFINITSEND. Ensuite, le message doit être enpaqueté dans ce buffer en utilisant PVMFPACK. Enfin, le message ainsi préparé peut être envoyé à un autre processus en appelant PVMFSEND ou en diffusion collective par PVMFMCAST. Un message est reçu en appelant une routine de réception soit bloquante, soit non bloquante, puis en dépaquetant les objets du buffer de réception. On peut paramétrer les arguments des routines de réception de telle sorte qu'elles acceptent tous les messages ou les messages d'une source précise, ou ceux munis d'une étiquette (tag) particulière ou encore un message d'une source donnée avec une étiquette précise.
Si le développeur utilise un unique buffer d'envoi (ce qui est le cas général), la seule routine nécessaire est PVMFINITSEND :
PVMFINITSEND (encoding, bufid)INTEGER encoding (IN) type du codage des données,
INTEGER bufid (OUT) identificateur du buffer.
Cet appel est effectué avant tout nouvel empaquetage de données dans le buffer : il efface le buffer d'envoi et en crée un nouveau pour le nouveau message. Le type de codage des données est spécifié par l'argument encoding et en sortie bufid contient l'identificateur du buffer. Les options de codage sont les suivantes :
- PvmDataDefault : codage XDR utilisé par défaut si PVM n'a pas d'information sur l'hétérogénéité de la machine parallèle virtuelle,
- PvmDataRaw : pas de codage des données, les messages sont laissés dans leur forme initiale,
- PvmDataInPlace : les données sont laissées à leur place, le buffer ne contient que les tailles et les adresses des objets à envoyer. Cela permet de ne pas dupliquer les données mais cela suppose aussi que le processus émetteur ne les modifiera pas.
Pour manipuler plusieurs buffers dans une même application, il faut utiliser les routines suivantes. Dans PVM, il n'y a qu'un seul buffer actif d'envoi et un seul buffer actif de réception à la fois. Par contre, il peut y avoir plusieurs buffers et ainsi empaqueter et envoyer des données avec eux. Les opérations d'empaquetage, envoi, réception et dépaquetage ne concernent que le buffer actif.
PVMFMKBUF (encoding, bufid)INTEGER encoding (IN) type du codage des données,
INTEGER bufid (OUT) identificateur du buffer.
La routine PVMFMKBUF crée un nouveau buffer d'envoi et précise la méthode de codage pour l'empaquetage des données. En retour, l'argument bufid contient l'identificateur. La routine PVMFFREEBUF libère le buffer d'identificateur bufid.
PVMFFREEBUF (bufid, irc)INTEGER bufid (IN) identificateur du buffer,
INTEGER irc (OUT) code de retour.
Cela doit être fait lorsque le message a été envoyé et que le buffer est devenu inutile. Ces appels ne sont pas nécessaires en cas d'utilisation de PVMFINITSEND.
Pour connaitre les identificateurs des buffers actifs d'envoi et de réception on utilise respectivement les routines suivantes :
PVMFGETSBUF (bufid)INTEGER bufid (OUT) identificateur du buffer d'envoi.
PVMFGETRBUF (bufid)INTEGER bufid (IN) identificateur du buffer de réception.
On peut spécifier le buffer actif d'envoi avec PVMFSETSBUF et de réception avec PVMFSETRBUF. Elles rendent actif le buffer d'identificateur bufid, sauvegardent l'état du buffer précédent et renvoient l'identificateur du buffer précédemment actif dans oldbuf :
PVMFSETSBUF (bufid, oldbuf)INTEGER bufid (IN) identificateur du buffer d'envoi activé,
INTEGER oldbuf (OUT) identificateur du buffer désactivé.
Si l'argument bufid est transmis à zéro dans PVMFSETSBUF ou PVMFSETRBUF alors le buffer courant est sauvegardé et il n'y a pas de buffer actif.PVMFSETRBUF (bufid, oldbuf)INTEGER bufid (IN) identificateur du buffer de réception activé,
INTEGER oldbuf (OUT) identificateur du buffer désactivé.
L'empaquetage de données en C se fait à l'aide de routines spécifiques à chaque type de données impliqué :
| Routine | Type C de la donnée |
| PVM_PKBYTE | char |
| PVM_PKCPLX | float |
| PVM_PKDCPLX | double |
| PVM_PKDOUBLE | double |
| PVM_PKFLOAT | float |
| PVM_PKINT | int |
| PVM_PKLONG | long |
| PVM_PKSHORT | short |
| PVM_PKSTR | char |
| PVM_PACKF | //// |
Chacune d'entre-elles empaquète un tableau du type de données dans le buffer d'envoi actif. Elles peuvent être appelées à plusieurs reprises pour un même message, ainsi un message peut contenir plusieurs tableaux de types de données différents. Les structures C doivent être envoyées en empaquetant chacun de leurs champs. Le dépaquetage doit se faire dans le même ordre que l'empaquetage. Les arguments de chaque routine sont dans l'ordre : un pointeur sur le premier élément à envoyer, le nombre total d'éléments du tableau, et le pas de parcours. Seule exception, la fonction PVM_PKSTR qui n'a besoin que d'un pointeur sur CHAR.
int info = pvm_pkbyte( char *cp, int nitem, int stride )
int info = pvm_pkcplx( float *xp, int nitem, int stride )
int info = pvm_pkdcplx ( double *zp, int nitem, int stride )
int info = pvm_pkdouble ( double *dp, int nitem, int stride )
int info = pvm_pkfloat ( float *fp, int nitem, int stride )
int info = pvm_pkint ( int *np, int nitem, int stride )
int info = pvm_pklong ( long *np, int nitem, int stride )
int info = pvm_pkshort ( short *np, int nitem, int stride )
int info = pvm_pkstr ( char *cp )
int info = pvm_packf ( const char *fmt, ... )
Une donnée de type complex est supposée être deux variables float consécutives, il en est de même pour le type double complexe avec deux variables double. Toutes les variables sont supposées être des pointeurs si les arguments nitem et stride sont présents, autrement il s'agit de scalaires. La fonction PVM_PACKF utilise un formatage similaire à la fonction C printf pour spécifier les données et la manière de les placer dans le buffer d'envoi (voir la manpage de PVM_PACKF). Une seule routine Fortran gère l'empaquetage des données : PVMFPACK :
PVMFPACK (what, xp, nitem, stride, irc)INTEGER what (IN) type de données à empaqueter,
<type> xp(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER nitem (IN) nombre d'éléments à envoyer,
INTEGER stride (IN) pas,
INTEGER irc (OUT) code de retour.
Le nombre de caractères dans une chaine de caractères doit être transmis à cette subroutine à l'aide de l'argument nitem. L'entier what précise le type de données envoyées, ses valeurs sont :
| Type | Valeur |
| STRING | 0 |
| BYTE1 | 1 |
| INTEGER2 | 2 |
| INTEGER4 | 3 |
| REAL4 | 4 |
| COMPLEX8 | 5 |
| REAL8 | 6 |
| COMPLEX16 | 7 |
La subroutine PVMFSEND donne une étiquette tag au message présent dans le buffer d'envoi actif et l'envoie immédiatement au processus destinataire tid :
PVMFSEND ( tid, tag, irc)INTEGER tid (IN) identificateur du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER irc (OUT) code de retour.
La routine PVMFMCAST donne une étiquette tag au message présent dans le buffer d'envoi actif et le diffuse à tous les tâches spécifiées dans le tableau tids (le processus émetteur exclu). Ce tableau a pour dimension ntask.
PVMFMCAST ( ntask, tids, tag, irc)INTEGER task (IN) nombre de tâches destinataires et dimension du tableau suivant,
INTEGER tids(*) (IN) tableau des identificateurs des processus destinataires,
INTEGER tag (IN) étiquette du message,
INTEGER irc (OUT) code de retour.
La routine PVMFPSEND permet d'empaqueter et d'envoyer un tableau de données de type simple à une tâche identifiée.
PVMFPSEND ( tid, tag, buffer, length, type, irc )INTEGER tid (IN) identificateur du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER buffer(*) (IN) donnée (adresse initiale) à envoyer,
INTEGER length (IN) taille du buffer (en multiple de la taille d'un élément),
INTEGER type (IN) type de données à envoyer,
INTEGER irc (OUT) code de retour.
En Fortran, le type des données est le même que pour PVMFPACK (voir tableau ci-dessus). En C l'argument type est lun des suivants :
| PVM_STR | PVM_FLOAT |
| PVM_BYTE | PVM_CPLX |
| PVM_SHORT | PVM_DOUBLE |
| PVM_INT | PVM_DCPLX |
| PVM_LONG | PVM_UINT |
| PVM_USHORT | PVM_ULONG |
Il y a différentes manières de réceptionner un message, de plus il n'y a pas obligatoirement une correspondance entre un send et un recv, i.e. entre un PVMFPSEND et un PVMFPRECV. N'importe laquelle des routines suivantes peut être utilisée pour réceptionner un message, qu'il soit envoyé en point-à-point ou collectivement.
PVMFRECV (tid, tag, bufid)INTEGER tid (IN) Identificateur du processus expéditeur,
INTEGER tag (IN) Etiquette du message,
INTEGER bufid (OUT) Identificateur du nouveau buffer actif.
Si l'argument tid vaut -1 alors tout processus est accepté comme expéditeur. Si tag vaut -1 alors tout message est accepté. Si bufid est négatif alors sa valeur correspond à un code d'erreur. La routine de réception bloquante PVMFRECV attend jusqu'à ce qu'un message portant l'étiquette tag arrive du processus tid (ou que leur valeur soit -1). Elle place le message dans un nouveau buffer de réception ainsi activé. Le précédent buffer activé est alors libéré à moins qu'il n'ait été sauvegardé par un appel à PVMSETRBUF.
PVMFNRECV (tid, tag, bufid)INTEGER tid (IN) Identificateur u processus expéditeur,
INTEGER tag (IN) Etiquette du message,
INTEGER bufid (OUT) Identificateur du nouveau buffer actif.
Si le message spécifié par tag n'est pas encore arrivé, alors la réception non bloquante PVMFNRECV rend la main avec l'argument bufid mis à zéro. Cette routine peut être appelée de nombreuses fois pour le même message et voir s'il est arrivé. S'il n'y a plus de travail à effectuer en attendant on peut alors mettre un PVMFRECV. Si un message d'étiquette tag arrive du processus tid (ou que leur valeur soit -1), elle le place dans un nouveau buffer de réception (ainsi crée) et renvoie l'identificateur du buffer. Le précédent buffer activé est alors libéré à moins qu'il n'ait été sauvegardé par un appel à PVMSETRBUF.
PVMFPROBE (tid, tag, bufid)INTEGER tid (IN) Identificateur du processus expéditeur,
INTEGER tag (IN) Etiquette du message,
INTEGER bufid (OUT) Identificateur du nouveau buffer actif.
Si le message spécifié par tag n'est pas encore arrivé alors PVMFPROBE renvoie l'argument bufid mis à zéro. Autrement, elle renvoie l'identificateur du buffer, mais n'effectue pas la réception. Cette routine peut être appelée de nombreuses fois pour le même message et voir s'il est arrivé. En complément, un appel à PVMFBUFINFO avec l'identificateur du buffer permet d'obtenir des informations à propos du message avant de le réceptionner.
PVMFBUFINFO (bufid, bytes, tag, tid, irc)INTEGER bufid (IN) Identificateur du buffer de réception,
INTEGER bytes (OUT) Longueur totale du message en octets,
INTEGER tag (OUT) Etiquette du message,
INTEGER tid (IN) Identificateur du processus source,
INTEGER irc (OUT) Code de retour.
Elle peut être employée pour déterminer l'étiquette et/ou la source précises d'un message pour lequel ces paramètres valent -1 (i.e. n'importe quelle étiquette et/ou n'importe quelle source).
PVM fournit une version "timeout" de réception, i.e. dans le cas ou un message en attente de réception ne sera jamais envoyé, une réception bloquante posera problème. Le développeur peut choisir d'abandonner au bout d'un temps d'attente donné. La routine PVMFTRECV permet ainsi au programmeur de spécifier un temps limite d'attente.
PVMFTRECV (tid, tag, sec, usec, bufid)INTEGER tid (IN) Identificateur du processus source,
INTEGER tag (IN) Etiquette du message,
INTEGER sec (IN) Définit le temps d'attente,
INTEGER usec (IN) Définit le temps d'attente,
INTEGER bufid (IN) Identificateur du buffer de réception.
La routine PVMFTRECV bloque jusqu'à ce qu'un message portant l'étiquette tag arrive du processus tid (ou que leur valeur soit -1). Elle place le message dans un nouveau buffer de réception ainsi activé (le précédent buffer activé est alors libéré à moins qu'il n'ait été sauvegardé par un appel à PVMSETRBUF). Si aucun message spécifié n'arrive durant le temps d'attente prédéfini alors PVMFTRECV rend la main (sans générer de message). Si la durée fournie est très grande alors PVMFTRECV se comporte comme PVMFRECV. Si la période est mise à zéro alors elle se comporte comme PVMFNRECV. Ainsi PVMFTRECV sert d'intermédiaire entre PVMFRECV et PVMFNRECV, i.e. entre les réception bloquante et non bloquante.
La routine PVMFPRECV combine les fonctionnalités d'une réception bloquante et du dépaquetage du buffer. La réception a lieu directement dans un buffer sans qu'il n'y ait de dépaquetage. C'est en quelque sorte l'équivalent en réception de PVMFPSEND :
PVMFPRECV ( tid, tag, buffer, length, type, atid, atag, alen, irc )INTEGER tid (IN) identificateur du processus destinataire,
INTEGER tag (IN) étiquette du message,
INTEGER buffer(*) (IN) donnée (adresse initiale) de réception,
INTEGER length (IN) taille du buffer (en multiple de la taille d'un élément),
INTEGER type (IN) type de données à recevoir,
INTEGER atid (OUT) véritable identificateur de l'expéditeur,
INTEGER atag (OUT) véritable étiquette du message,
INTEGER alen (OUT) véritable longueur du message,
INTEGER irc (OUT) code de retour.
Le dépaquetage de données en C se fait à l'aide de routines spécifiques à chaque type de données impliqué :
| Routine | Type C de la donnée |
| PVM_UPKBYTE | char |
| PVM_UPKCPLX | float |
| PVM_UPKDCPLX | double |
| PVM_UPKDOUBLE | double |
| PVM_UPKFLOAT | float |
| PVM_UPKINT | int |
| PVM_UPKLONG | long |
| PVM_UPKSHORT | short |
| PVM_UPKSTR | char |
| PVM_UNPACKF | //// |
Chacune d'entre-elles dépaquète un tableau du type de données dans le buffer de réception actif. Elles doivent correspondre à leur analogue d'empaquetage pour les arguments de type, de nombre d'éléments et de pas; le dépaquetage doit se faire dans le même ordre que l'empaquetage. Les arguments de chaque routine sont dans l'ordre : un pointeur sur le premier élément à envoyer, le nombre total d'éléments du tableau, et le pas de parcours. Seule exception, la fonction PVM_UPKSTR qui n'a besoin que d'un pointeur sur char.
int info = pvm_upkbyte( char *cp, int nitem, int stride )
int info = pvm_upkcplx( float *xp, int nitem, int stride )
int info = pvm_upkdcplx ( double *zp, int nitem, int stride )
int info = pvm_upkdouble ( double *dp, int nitem, int stride )
int info = pvm_upkfloat ( float *fp, int nitem, int stride )
int info = pvm_upkint ( int *np, int nitem, int stride )
int info = pvm_upklong ( long *np, int nitem, int stride )
int info = pvm_upkshort ( short *np, int nitem, int stride )
int info = pvm_upkstr ( char *cp )
int info = pvm_unpackf ( const char *fmt, ... )
Une donnée de type complex est supposée être deux variables float consécutives, il en est de même pour le type double complexe avec deux variables double. Toutes les variables sont supposées être des pointeurs si les arguments nitem et stride sont présents, autrement il s'agit de scalaires. La fonction PVM_UNPACKF utilise un formatage similaire à la fonction C printf pour spécifier les données et la manière de les placer dans le buffer d'envoi (voir la manpage de PVM_UNPACKF). Une seule routine Fortran gère le dépaquetage des données : PVMFUNPACK.
PVMFUNPACK (what, xp, nitem, stride, irc)INTEGER what (IN) type de données à dépaqueter,
<type> xp(*) (IN) donnée (adresse initiale) à dépaqueter,
INTEGER nitem (IN) nombre d'éléments à recevoir,
INTEGER stride (IN) pas,
INTEGER irc (OUT) code de retour.
Le nombre de caractères dans une chaine de caractères doit être transmis à cette subroutine à l'aide de l'argument nitem. L'entier what précise le type de données envoyées, ses valeurs sont :
| Type | Valeur |
| STRING | 0 |
| BYTE1 | 1 |
| INTEGER2 | 2 |
| INTEGER4 | 3 |
| REAL4 | 4 |
| COMPLEX8 | 5 |
| REAL8 | 6 |
| COMPLEX16 | 7 |
Gestion des groupes de processus
On regroupe des processus PVM à l'aide de la routine PVMFJOINGROUP qui permet d'inclure le processus appelant dans un groupe. En sortie, ce processus reçoit son rang (numéro d'instance) dans le groupe, une valeur (unique au sein du groupe) comprise entre 0 et le nombre de processus du groupe - 1, qui permet de l'identifier. Le premier processus qui effectue l'appel crée le groupe.PVMFJOINGROUP (group, irank)CHARACTER(*) group (IN) nom du groupe de processus,
INTEGER irank (OUT) rang du processus.
De même, on peut quitter un groupe à l'aide de la routine PVMFLVGROUP:
PVMFLVGROUP (group, irc)CHARACTER(*) group (IN) nom du groupe de processus,
INTEGER irc (OUT) code de retour.
N'importe quelle tâche PVM peut rejoindre ou quitter un groupe de processus, n'importe quand et sans devoir en informer une autre tâche. En cas de sortie et de réentrée, le numéro d'instance (le rang) n'est pas forcément le même : la tâche entrante reçoit le plus petit numéro disponible. En cas de sortie de tâches du groupe, c'est au développeur de maintenir un ensemble contigu des numéros d'instance si l'algorithme le nécessite. De plus, un processus peut appartenir à plusieurs groupes; enfin elle peut diffuser des messages vers un groupe dont elle ne fait pas partie.
La routine PVMFGETTID renvoie l'identificateur d'un processus dont on connait le numéro d'instance dans un groupe donné :
PVMFGETTID (group, irang, tid)CHARACTER(*) group (IN) nom du groupe de processus,
INTEGER irank (IN) numéro d'instance du processus dans le groupe,
INTEGER tid (OUT) identificateur du processus.
Deux processus qui n'ont pas de connaissance réciproque peuvent obtenir l'identificateur de l'autre processus en intégrant un groupe commun. La routine PVMFGETINST renvoie le numéro d'instance d'un processus dont on connait l'identificateur et un groupe d'appartenance :
PVMFGETINST (group, tid, irang)CHARACTER(*) group (IN) nom du groupe de processus,
INTEGER tid (IN) identificateur du processus,
INTEGER irank (OUT) numéro d'instance du processus dans le groupe.
La routine PVMFGSIZE retourne le nombre de processus d'un groupe donné :
PVMFGSIZE (group, size)CHARACTER(*) group (IN) nom du groupe de processus,
INTEGER size (OUT) nombre de processus dans le groupe.
En appelant PVMFBARRIER le processus bloque jusqu'à ce qu'un total de count membres d'un groupe ont fait de même.
PVMFBARRIER (group, count, irc)CHARACTER(*) group (IN) nom du groupe de processus,
INTEGER count (IN) identificateur du processus,
INTEGER irc (OUT) code de retour.
En général count devrait être égal au nombre de membres d'un groupe. Fournir un nombre de processus est nécessaire du fait de la gestion dynamique des processus au sein des groupes PVM. En effet, PVM ne peut pas connaitre à un instant donné le nombre de processus. Les situations suivantes engendrent des erreurs : appeler PVMFBARRIER avec un groupe par un processus qui n'en fait pas partie, différents processus effectuent l'appel mais avec des valeurs différentes de count.
La routine PVMFBCAST assigne une étiquette tag et effectue une diffusion générale à toutes les tâches membres du groupe spécifié en argument (à l'exception du processus émetteur) au moment où l'appel est effectué. Si des processus intègrent le groupe durant le broadcast, il est possible qu'ils ne reçoivent pas le message; par contre en cas de sortie, ils reçoivent le message.
PVMFBCAST (group, tag, irc)CHARACTER(*) group (IN) nom du groupe de processus,
INTEGER tag (IN) étiquette du message,
INTEGER irc (OUT) code de retour.
La routine PVMFREDUCE effectue une opération d'arithmétique globale au sein d'un groupe, par exemple une somme globale ou la recherche du maximum. Le résultat est reçu par le processus appelé root.
PVMFREDUCE (func, data, count, type, tag, group, root, irc)EXTERNAL func (IN) fonction à appliquer,
<type> data (IN/OUT) donnée (adresse initiale) à réduire,
INTEGER count (IN) nombre d'éléments dans le tableau,
INTEGER type (IN) type de données des éléments du tableau,
INTEGER tag (IN) étiquette du message,
CHARACTER(*) group (IN) nom du groupe de processus,
INTEGER root (IN) rang du processus destinataire de l'opération,
INTEGER irc (OUT) code de retour.
func est le nom d'une fonction appliquée aux données transmises dans data. Ses valeurs prédéfinies sont :
| PvmMax | PvmMin | PvmSum | PvmProduct |
Il est possible de construire ses propres fonctions.
Ces fonctions sont implantées pour les types de données suivants :
| Type PVM de la donnée | Type C de la donnée | Type PVM de la donnée | Type Fortran de la donnée |
| PVM_BYTE | byte | BYTE1 | CHARACTER |
| PVM_SHORT | short | INTEGER2 | INTEGER*2 |
| PVM_INT | int | INTEGER4 | INTEGER*4 |
| PVM_FLOAT | float | INTEGER8 | INTEGER*8 |
| PVM_CPLX | complex | REAL4 | REAL*4 |
| PVM_DOUBLE | double | REAL8 | REAL*8 |
| PVM_LONG | long int | COMPLEX8 | COMPLEX*8 |
| PVM_USHORT | unsigned short int | COMPLEX16 | COMPLEX*16 |
| PVM_UINT | unsigned int | ||
| PVM_ULONG | unsigned long |
L'opération de réduction est effectuée élément par élément au sein du tableau data. Par exemple, si le tableau contient deux nombre réels et la fonction de réduction est PvmMax alors le tableau résultat data du processus root contiendra deux valeurs : la première correspond au produit de tous les premiers réels et la seconde au produit de tous les seconds réels.
La routine PVMFSCATTER distribue un tableau à chaque membre d'un groupe de processus. Le processus émetteur, est identifié par son rang dans le groupe.Tous les membres du groupe doivent appeler cette subroutine pour que chacun reçoive une portion du tableau data. Le i-ème membre du groupe reçoit num éléments de type type du tableau data à partir de l'indice i*num , qui sont stockés dans son tableau result.
PVMFSCATTER ( result, data, num, type, tag, group, root, irc )<type> result(*) (OUT) donnée (adresse initiale) de réception,
<type> data(*) (IN) donnée (adresse initiale) à distribuer,
INTEGER num (IN) nombre d'éléments à envoyer à chaque membre du groupe,
INTEGER type (IN) type de données des éléments du tableau,
INTEGER tag (IN) étiquette du message,
CHARACTER(*) group (IN) nom du groupe de processus,
INTEGER root (IN) rang du processus auteur de l'opération,
INTEGER irc (OUT) code de retour.
La listes des type de données figure dans le tableau ci-dessus.
Dans un appel à PVMFGATHER, chaque processus du groupe (root inclus) envoie ses données au processus root qui les reçoit et les stocke dans l'ordre des rangs des processus. Tous les membres du groupe doivent appeler cette subroutine pour pouvoir envoyer une portion du tableau data. Le i-ème membre du groupe envoie num éléments de type type du tableau data, qui sont stockés dans le tableau result du processus root à partir de l'indice i*num.
PVMFGATHER ( result, data, num, type, tag, group, root, irc )<type> result(*) (OUT) donnée (adresse initiale) de réception,
<type> data(*) (IN) donnée (adresse initiale) à fusionner,
INTEGER num (IN) nombre d'éléments envoyés par chaque membre du groupe,
INTEGER type (IN) type de données des éléments du tableau,
INTEGER tag (IN) étiquette du message,
CHARACTER(*) group (IN) nom du groupe de processus,
INTEGER root (IN) rang du processus auteur de l'opération,
INTEGER irc (OUT) code de retour.
La liste des type de données figure dans le tableau ci-dessus.
Ces deux subroutines ne sont pas bloquantes. Si une tâche appelle une de ces fonctions et sort du groupe avant que le processus root n'ait effectué lui-même l'appel alors une erreur peut survenir.
Exemples de programme PVM Maître/Esclave