Request

De Wiki de Calcul Québec
Aller à : Navigation, rechercher
Autres langues :anglais 100% • ‎français 100%

Pour certaines applications il est difficile d'assurer une répartition équitable de la charge de travail sur tous les processeurs. Lorsque le nombre de processeurs est suffisamment élevé et que les tâches peuvent facilement être subdivisées en plusieurs petites tâches, il est intéressant d'utiliser une approche maître-esclave.

Nous illustrons l'utilisation de cette méthode dans un cas où nous étudions un grand nombre de particules. Le volume total contenant les particules a été préalablement subdivisé en un très grand nombre de petits éléments de volume. Dans cette application, nous supposons que chaque processeur doit générer aléatoirement la position des particules dans ces petits volumes.

Vous noterez que, dans une approche maître-esclave, la notion de requête (type MPI_Request) est importante. Ces objets sont créés par le processeur maître lorsqu'il démarre une recherche pour un message provenant de n'importe quel processeur. Puis par la suite, ils peuvent être vérifiés aussi souvent que l'on désire. Ils peuvent être également détruits par le processeur maître.

Cet exemple illustre l'utilisation des commandes MPI_Irecv et MPI_Wait en MPI pour des communications non synchronisées. Le processeur 0 est appelé processeur maître et les autres sont les processeurs esclaves. Ce type d'approche est utile lorsqu'il est difficile de bien répartir l'ensemble des tâches. Il faut que le nombre de tâches soit divisé en un nombre très grand. Aussitôt qu'un processeur a terminé sa tâche, il contacte le processeur maître pour en recevoir une nouvelle.


Fichier : request.c
/*--------------------------------------------------------
 Auteur: Steve Allen
         Centre de calcul scientifique
         Université de Sherbrooke
 
 Dernière révision: octobre 2007
--------------------------------------------------------*/
 
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
 
int main(int argc,char** argv)
{
   int         master = 0;
   int         finish_flag = -1;
   int         myrank, nprocs;
   int         nvol, nptc, totptc;
   int         i, nfinish, *buf_recv, nslaves, last;
   float       x, y, z;
   MPI_Request *request;
   MPI_Status  status;
 
   /* Initialisation*/
   MPI_Init(&argc, &argv);
   MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
   MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
 
   /* Le nombre de processeurs doit être au minimum 2 */
   if( nprocs < 2 )
   {
       printf("%d processeur n'est pas suffisant pour cet exemple\n", nprocs);
       MPI_Finalize();
       exit( 1 );
    }
 
   nvol = 0;
   if (myrank == master){
 
      /* Opérations du processeur maître */
      if( argc > 1 )
      {
          nvol = atoi( argv[1] );
      }
      if( nvol <= 0 ) nvol = 6000;
      printf("Generating nvol=%d with %d procs\n", nvol, nprocs-1);
 
      nslaves = nprocs - 1;
      buf_recv = (int*) malloc( nslaves * sizeof(int) );
      request = (MPI_Request*) malloc( nslaves * sizeof(MPI_Request) );
      last = 0;
      nfinish = 0;
 
      /* Envoie les messages de début des travaux */
      for( i = 0; i < nslaves; i++ )
      {
         if( last < nvol )
         {
            last++;
            MPI_Send( &last, 1, MPI_INT, i+1, 0, MPI_COMM_WORLD );
            MPI_Irecv( &(buf_recv[i]), 1, MPI_INT, i+1, i+1, MPI_COMM_WORLD, &(request[i]) );
         }
         else
         {
            MPI_Send( &finish_flag, 1, MPI_INT, i+1, 0, MPI_COMM_WORLD );
            nfinish++;
         }
      }
      while( nfinish < nslaves )
      {
         /* Attend qu'un processeur ait terminé */
         MPI_Waitany( nslaves, request, &i, &status );
         if( last < nvol )
         {
            /* S'il reste des cas à traiter */
            last++;
            MPI_Send( &last, 1, MPI_INT, i+1, 0, MPI_COMM_WORLD );
            MPI_Irecv( &(buf_recv[i]), 1, MPI_INT, i+1, i+1, MPI_COMM_WORLD, &(request[i]) );
         }
         else
         {
            /* Si c'est fini */
            MPI_Send( &finish_flag, 1, MPI_INT, i+1, 0, MPI_COMM_WORLD );
            nfinish++;
         }
      }
      free( request );
      free( buf_recv );
 
   } else {
 
      /* Tâches des processeurs esclaves */
      totptc = 0;
      nvol = 0;
      buf_recv = (int*) malloc( sizeof(int) );
      MPI_Recv( buf_recv, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status );
 
      /* Tant que tous les cas ne sont pas couverts */
      while( *buf_recv != finish_flag )
      {
         /* Génère des particules pour le cas reçu */
         nptc = (int) ( ( (float) rand() ) / RAND_MAX * 2500 ) + 2500;
         for( i = 0; i < nptc; i++ )
         {
            x = ( (float) rand() ) / RAND_MAX;
            y = ( (float) rand() ) / RAND_MAX;
            z = ( (float) rand() ) / RAND_MAX;
         }
         totptc += nptc;
         nvol++;
         MPI_Send( &nptc, 1, MPI_INT, 0, myrank, MPI_COMM_WORLD );
         MPI_Recv( buf_recv, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status );
      }
      free( buf_recv );
 
      printf("Generated %d vol with a total of %d ptcs\n", nvol, totptc);
   }
 
   MPI_Barrier( MPI_COMM_WORLD );
   MPI_Finalize();
}


Outils personnels
Espaces de noms

Variantes
Actions
Navigation
Ressources de Calcul Québec
Outils
Partager