Previous Next Contents

Appendix B    Autres librairies

B.1  PVM3.4

La version 3.4 est la toute dernière version de PVM. Elle ajoute quelques fonctionnalités type MPI, et en particulier:

B.1.1  Contextes de Communication

C'est un ``tag'' supplémentaire qui permet en particulier de bien filtrer les messages utilisateurs des messages systèmes (ou entre groupes, ou entre applications différentes). Pour ces nouveaux ``tag'', il n'y a pas de possibilité de ``wildcard'' (filtrage à la réception avec TAG=-1).

Ces ``tags'' assurent un certain nombre de propriétés. Toute création d'un nouveau contexte définit un unique tag pour toute une machine PVM. De plus les tâches filles héritent du contexte du père.

A noter que cette extension de PVM ne rend pas obsolète les anciens programmes PVM. Les principales commandes associées sont:

Dans la pratique, une tâche demande un nouveau contexte et le distribue à toutes les autres taches par newcontext=pvm_newcontext(). Puis les autres tâches se mettent au nouveau contexte pendant les appels aux fonctionnalités privées de la première tâche par:

oldcontext=pvm_setcontext(newcontext);
/* communications sures */
newcontext=pvm_setcontext(oldcontext);
pvm_freecontext(newcontext);
/* on revient a l'ancien contexte */

B.1.2  Handlers

Les ``handlers'' permettent d'exécuter une fonction C à la réception d'un message spécifique. Ils agissent comme des interruptions (qui n'interrompent le cours du programme que uniquement pendant les appels à la librairie PVM). La fonction C (il n'y a aucune restriction d'usage) est appelée quand un message correspond à un pattern (context,msgtag,source) donné.

Les principales commandes correspondantes sont:

B.1.3  Messages persistants

Les messages persistants sont des messages ``uni-directionnels'', similaire au ``tuple-space'' de Linda. Les tâches PVM peuvent enregister et récupérer des messages par leurs noms: cela organise de fait une base de données distribuée pour les processus. Il est également possible de ranger plusieurs messages sous un même nom.

Les principales commandes sont:

B.2  MPI

MPI (``Message Passing Interface'') est le prochain standard de fait (voir http: //www.mcs.anl.gov/mpi/). MPI fait l'objet fin 1992 d'un groupe de travail de 40 experts industriels et académiques. Le premier standard MPI-1 est réalisé fin 1993. Le principe est que chaque vendeur de supercalculateurs implémente sa propre API propriétaire en respectant le standard. Cela fait que MPI est particulièrement bien optimisé sur un grand nombre d'architectures de super-calculateurs. Mais le système n'est pas basé comme PVM sur la notion de machine virtuelle, et les implémentations sont moins bien étudiées pour les réseaux de stations (éventuellement hétérogènes). L'abstraction utilisée par MPI est celle de topologie de passage de messages. La deuxième version du standard a commencé début 1995, et le premier brouillon a été publié fin 1996.

B.2.1  MPI-1

Le premier standard décrit 128 fonctions, mais pas d'équivalent de pvm_spawn. Les processus sont donc définis de façon statique uniquement. MPI-1 comprend une notion de communicator englobant les notions de contextes (de PVM3.4) et les groupes de processus (de PVM3.3).

La grande force du standard est le fait qu'il inclut énormément de fonctions de communication point à point et entre groupes de processus. Ces fonctions reposent sur des fonctions de définition de topologies de communication ainsi que de définitions de datatypes qui décrivent des messages pris à des endroits non contigus de la mémoire.

B.2.2  MPI-2

Le deuxième standard décrit 120 fonctions de plus et en particulier des fonctions de communication collectives non-bloquantes et un MPI_SPAWN (équivalent de pvm_spawn).

MPI-2 intègre également des communications unidirectionnelles (les messages persistants de PVM3.4) et l'équivalent des handlers de PVM3.4. MPI-2 devrait avoir des fonctions pour gérer la tolérance aux pannes.

Il existe quelques versions gratuites actuellement implémentant en partie les standards MPI dont,

Sinon, il existe des versions contructeurs (non gratuites...) sur CRAY, SGI, IBM etc.

B.2.3  Exemple

On donne ci-après un petit exemple de code MPI (fourni avec la distribution standard).

/* Transmet un message dans un systeme a 2 processus. */
#include <mpi.h>
#define BUFSIZE                64
int                        buf[BUFSIZE];
int main(argc, argv)
     int                        argc;
     char                        *argv[];
{
  int                size, rank;
  MPI_Status        status;
  /* Initialisation de MPI. */
  MPI_Init(&argc, &argv);
  /* On verifie le nombre de processus presents */
  MPI_Comm_size(MPI_COMM_WORLD, &size);
  if (2 != size) {
    MPI_Finalize();  /* comme pvm_exit */
    return(1);
  }
  
  /* Determine son rang dans le groupe "World" */
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  
  /* L'envoyeur aura rang 0, le receveur, rang 1 */
  /* Si rang 0 envoyer au rang 1 */
  if (0 == rank) {
    MPI_Send(buf, BUFSIZE, MPI_INT, 1, 11, MPI_COMM_WORLD);
  }
  /* Si rang 1 recevoir du rang 0 */
  else {
    MPI_Recv(buf,BUFSIZE,MPI_INT,0,11,MPI_COMM_WORLD,&status);
  }
  
  MPI_Finalize();
  return(0);
}
Exemple:

#include <mpi.h>
#define WORKTAG                1
#define DIETAG                2
#define NUM_WORK_REQS        200
static void                master();
static void                slave();

/* Ce programme est MIMD, mais est ecrit SPMD pour */
/* etre plus simple a lancer */
int main(argc, argv)
     int                        argc;
     char                        *argv[];
{
  int                myrank;
  MPI_Init(&argc, &argv);
  MPI_Comm_rank(MPI_COMM_WORLD,        /* groupe de tout le monde */
                &myrank);        /* 0 a N-1 */
  
  if (myrank == 0) {
    master();
  } else {
    slave();
  }
  
  MPI_Finalize();
  return(0);
}
/* Le maitre envoie des demandes de travaux aux */
/* esclaves puis collecte les resultats */
static void master()
{
  int                ntasks, rank, work;
  double        result;
  MPI_Status        status;
  
  MPI_Comm_size(MPI_COMM_WORLD,&ntasks); /* #processus */
  /* Initialiser les esclaves */
  work = NUM_WORK_REQS;                /* simulation */
  for (rank = 1; rank < ntasks; ++rank) {
    MPI_Send(&work,                /* tampon de messages */
             1,                /* un seul element */
             MPI_INT,        /* de ce type */
             rank,                /* au proc de ce rang */
             WORKTAG,        /* message "travail" */
             MPI_COMM_WORLD);/* contexte */
    work--;
  }
  /* Recoit un resultat de n'importe quel esclave et */
  /* renvoie un nouveau travail jusqu'a ce que les */
  /* requetes soient epuisees */
  while (work > 0) {
    MPI_Recv(&result,        /* tampon de messages */
             1,                /* un seul element */
             MPI_DOUBLE,        /* de ce type */
             MPI_ANY_SOURCE,        /* de n'importe qui */
             MPI_ANY_TAG,        /* n'importe quel message */
             MPI_COMM_WORLD,        /* communicator */
             &status);        /* info */
    
    MPI_Send(&work, 1, MPI_INT, status.MPI_SOURCE,
             WORKTAG, MPI_COMM_WORLD);
    
    work--;                        /* simulation */
  }
  /* Recoit les resultats des esclaves */
  for (rank = 1; rank < ntasks; ++rank) {
    MPI_Recv(&result, 1, MPI_DOUBLE, MPI_ANY_SOURCE,
             MPI_ANY_TAG, MPI_COMM_WORLD, &status);
  }
  /* Dit aux esclaves de terminer */
  for (rank = 1; rank < ntasks; ++rank) {
    MPI_Send(0, 0, MPI_INT, rank, DIETAG, MPI_COMM_WORLD);
  }
}
/* Chaque esclave accepte les requetes de travaux et */
/* retourne les resultats jusqu'a requete terminaison */
static void slave()
{
  double        result;
  int                work;
  MPI_Status        status;
  for (;;) {
    MPI_Recv(&work, 1, MPI_INT, 0, MPI_ANY_TAG,
             MPI_COMM_WORLD, &status);
    /* Verifie le tag du message */
    if (status.MPI_TAG == DIETAG) {
      return;
    }
    sleep(2);
    result = 6.0;                /* simulation */
    MPI_Send(&result, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
  }
}

B.3  Comparaison PVM, MPI

En général MPI a de meilleures performances que PVM (mais elles restent quand même très comparables même sur un Cray T3D ou un IBM SP2). PVM sacrifie les performances pour être portable sur un réseau hétérogène. Par contre MPI est non portable sur réseau de stations (pas de méthode standard pour démarrer MPI, ni de notion de machine virtuelle). MPI a plus de primitives de communications, mais il y a encore un certain nombre de problèmes non-résolus pour les pannes (en particulier vis-à-vis des communicators).

En conclusion, PVM3.4 et MPI-2 se ressemblent maintenant beaucoup, aux performances près. Parmi les projets en cours, on trouve d'ailleurs un projet de ``convergence'' PVM et MPI qui se nomme PVMMPI.


Previous Next Contents