Allgather

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

Cet exemple illustre l'utilisation de la fonction MPI_allgather qui rassemble les données de plusieurs tâches en un vecteur et distribue ce vecteur à toutes les tâches. Donc, l'équivalent d'un MPI_Gather suivi d'un MPI_Bcast, mais plus efficace!

Chaque tâche prépare (initialise) un vecteur de réels sendbuff de dimension buffsize. Ensuite la fonction MPI_Allgather rassemble ces données dans le tableau recvbuff de chaque tâche. Avant et après l'étape de communication, la somme de chacun des vecteurs est affichée à l'écran pour vérification.

En Fortran

Fichier : allgather.f
!--------------------------------------------------------
!          sendbuff
!   
!          ########
!          #      #
!        0 #  AA  #
!          #      #
!          ########
!     T    #      #
!        1 #  BB  #
!     a    #      #
!          ########
!     c    #      #
!        2 #  CC  #                                   AVANT
!     h    #      #
!          ########
!     e    #      #
!        3 #  DD  #
!     s    #      #
!          ########
!          #      #
!        4 #  EE  #
!          #      #
!          ########
!          
!            <---------- recvbuff ---------->
!
!          ####################################
!          #      #      #      #      #      #
!        0 #  AA  #  BB  #  CC  #  DD  #  EE  #
!          #      #      #      #      #      #
!          ####################################
!     T    #      #      #      #      #      #
!        1 #  AA  #  BB  #  CC  #  DD  #  EE  #
!     a    #      #      #      #      #      #
!          ####################################
!     c    #      #      #      #      #      #
!        2 #  AA  #  BB  #  CC  #  DD  #  EE  #       APRES
!     h    #      #      #      #      #      #
!          ####################################
!     e    #      #      #      #      #      #
!        3 #  AA  #  BB  #  CC  #  DD  #  EE  #
!     s    #      #      #      #      #      #
!          ####################################
!          #      #      #      #      #      #
!        4 #  AA  #  BB  #  CC  #  DD  #  EE  #
!          #      #      #      #      #      #
!          ####################################
!   
! Auteur: Carol Gauthier
!         Centre de Calcul scientifique
!         Universite de Sherbrooke
!
! Derniere revision: Aout 2004
!--------------------------------------------------------
Program Exemple_MPI
 
  include 'mpif.h'
  integer ierr,ntasks,taskid,itask,status(MPI_STATUS_SIZE)
  integer i,j,k,buffsize,jtask
  character argtmp*12
  real(8) inittime,recvtime,totaltime,rand,buffsum
 
  real(8),allocatable,dimension(:) :: sendbuff
  real(8),allocatable,dimension(:,:) :: recvbuff
 
  !---------------------------------------------------------------
  ! Initialisation de MPI. Il est important de placer cet appel   
  ! au debut du programme, immediatement apres les declarations   
  call MPI_INIT( ierr )
 
  !---------------------------------------------------------------
  ! Obtenir le nombre de taches MPI et le numero d'identification
  ! de la tache courante
  call MPI_COMM_SIZE(MPI_COMM_WORLD,ntasks,ierr)
  call MPI_COMM_RANK(MPI_COMM_WORLD,taskid,ierr)
 
  !---------------------------------------------------------------
  ! Dimension  du vecteur a partir des arguments
  call getarg(1,argtmp)
  read(argtmp,'(I12)')buffsize
 
  !---------------------------------------------------------------
  ! Affichage de la description de l'exemple.
  if ( taskid.eq.0 )then
    write(6,'(A)')
    write(6,'(A)')"##########################################################"
    write(6,'(A)')
    write(6,'(A)')" Exemple 10"
    write(6,'(A)')
    write(6,'(A)')" Communication collective : MPI_Allgather"
    write(6,'(A)')
    write(6,'(A,I12)')" Dimension du vecteur:",buffsize
    write(6,'(A,I5)')" Nombre total de taches:",ntasks
    write(6,'(A)')
    write(6,'(A)')"##########################################################"
    write(6,'(A)')
    write(6,'(A)')"                --> AVANT COMMUNICATION <--"
    write(6,'(A)')
  endif
 
  !---------------------------------------------------------------
  ! Allocation de la memoire 
  allocate( sendbuff(0:buffsize-1) )
  allocate( recvbuff(0:buffsize-1,0:ntasks-1) )
 
  !-----------------------------------------------------------------
  ! Initialisation du/des vecteurs et/ou tableaux.
  call srand(taskid*10)
  do i=0,buffsize-1
    sendbuff(i)=rand()
  end do
 
  !-----------------------------------------------------------------
  ! Affichage avant communication.
 
  call MPI_Barrier(MPI_COMM_WORLD,ierr)
 
  buffsum=0.0
  do i=0,buffsize-1
    buffsum=buffsum+sendbuff(i)
  end do
 
  write(6,'(A,I3,A,E14.8)')"Tache",taskid,": Somme du vecteur = ",buffsum
 
  call MPI_Barrier(MPI_COMM_WORLD,ierr)   
 
  !-----------------------------------------------------------------
  ! Communication
 
  inittime = MPI_Wtime()
 
  call MPI_Allgather(sendbuff,buffsize,MPI_REAL8, &
  &                  recvbuff,buffsize,MPI_REAL8, &
  &                  MPI_COMM_WORLD,ierr)
 
  totaltime = MPI_Wtime()
 
  !-----------------------------------------------------------------
  ! Affichage apres communication.
  if(taskid.eq.0)then
    write(6,*)
    write(6,'(A)')"##########################################################"
    write(6,*)
    write(6,'(A)')"                --> APRES COMMUNICATION <--"
    write(6,*)
  end if
  do jtask=0,ntasks-1
    call MPI_Barrier(MPI_COMM_WORLD,ierr)
    if(taskid.eq.jtask)then
      write(6,*)
      do itask=0,ntasks-1
        buffsum=0.0
        do i=0,buffsize-1
          buffsum=buffsum+recvbuff(i,itask)
        end do
        write(6,'(A,I3,A,I3,A,E14.8)')"Tache ",taskid,": Somme du vecteur reçu par la tache ",itask, &
        &                             "= ",buffsum
      end do
    end if
  end do
  call MPI_Barrier(MPI_COMM_WORLD,ierr)
 
  if(taskid.eq.0)then
    write(6,*)
    write(6,'(A)')"##########################################################"
    write(6,'(A,F5.2,A)')" Temps total de communication : ",totaltime," seconds"
    write(6,'(A)')"##########################################################"
    write(6,*)
  end if
 
  !-----------------------------------------------------------------
  ! Liberation de la memoire
  deallocate(sendbuff)
  deallocate(recvbuff)
 
  !-----------------------------------------------------------------
  ! Finalisation de MPI
 
  call MPI_FINALIZE( ierr )
end


En C

Fichier : allgather.c
/*--------------------------------------------------------
          sendbuff
 
          ########
          #      #
        0 #  AA  #
          #      #
          ########
     T    #      #
        1 #  BB  #
     a    #      #
          ########
     c    #      #
        2 #  CC  #                                   AVANT
     h    #      #
          ########
     e    #      #
        3 #  DD  #
     s    #      #
          ########
          #      #
        4 #  EE  #
          #      #
          ########
 
            <---------- recvbuff ---------->
 
          ####################################
          #      #      #      #      #      #
        0 #  AA  #  BB  #  CC  #  DD  #  EE  #
          #      #      #      #      #      #
          ####################################
     T    #      #      #      #      #      #
        1 #  AA  #  BB  #  CC  #  DD  #  EE  #
     a    #      #      #      #      #      #
          ####################################
     c    #      #      #      #      #      #
        2 #  AA  #  BB  #  CC  #  DD  #  EE  #       APRES
     h    #      #      #      #      #      #
          ####################################
     e    #      #      #      #      #      #
        3 #  AA  #  BB  #  CC  #  DD  #  EE  #
     s    #      #      #      #      #      #
          ####################################
          #      #      #      #      #      #
        4 #  AA  #  BB  #  CC  #  DD  #  EE  #
          #      #      #      #      #      #
          #################################### 
 
 Auteur: Carol Gauthier
         Centre de Calcul scientifique
         Universite de Sherbrooke
 
 Derniere revision: Septembre 2005
--------------------------------------------------------*/
 
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "math.h"
#include "mpi.h"
 
int main(int argc,char** argv)
{
   /*===============================================================*/
   /* Declaration des variables                                     */
   int          taskid, ntasks;
   MPI_Status   status;
   int          ierr,i,j,itask,jtask;
   int	        buffsize;
   double       *sendbuff,**recvbuff,buffsum;
   double       inittime,totaltime;
 
   /*===============================================================*/
   /* Initialisation de MPI. Il est important de placer cet appel   */
   /* au debut du programme, immediatement apres les declarations   */
   MPI_Init(&argc, &argv);
 
   /*===============================================================*/
   /* Obtenir le nombre de taches MPI et le numero d'identification */
   /* de la tache courante taskid                                   */
   MPI_Comm_rank(MPI_COMM_WORLD,&taskid);
   MPI_Comm_size(MPI_COMM_WORLD,&ntasks);
 
   /*===============================================================*/
   /* Obtenir buffsize a partir des arguments.                      */
   buffsize=atoi(argv[1]);
 
   /*===============================================================*/
   /* Affichage de la description de l'exemple.                     */
   if ( taskid == 0 ){
     printf("\n\n\n");
     printf("##########################################################\n\n");
     printf(" Exemple 10 \n\n");
     printf(" Communication collective : MPI_Allgather \n\n");
     printf(" Dimension de chaque vecteur: %d\n",buffsize);
     printf(" Nombre total de taches: %d\n\n",ntasks);
     printf("##########################################################\n\n");
     printf("                --> AVANT COMMUNICATION <--\n\n");
   }
 
   /*=============================================================*/
   /* Allocation de la memoire.                                   */ 
   sendbuff=(double *)malloc(sizeof(double)*buffsize);
   recvbuff=(double **)malloc(sizeof(double *)*ntasks);
   recvbuff[0]=(double *)malloc(sizeof(double)*ntasks*buffsize);
   for(i=1;i<ntasks;i++)recvbuff[i]=recvbuff[i-1]+buffsize;
 
   /*=============================================================*/
   /* Initialisation du/des vecteurs et/ou tableaux               */
   srand((unsigned)time( NULL ) + taskid);
   for(i=0;i<buffsize;i++){
       sendbuff[i]=(double)rand()/RAND_MAX;
   }
 
   /*==============================================================*/
   /* Affichage avant communication.                               */
 
   MPI_Barrier(MPI_COMM_WORLD);
 
   buffsum=0.0;
   for(i=0;i<buffsize;i++){
     buffsum=buffsum+sendbuff[i];
   }
   printf("Tache %d : Somme du vecteur = %e \n",taskid,buffsum);
 
   /*===============================================================*/
   /* Communication.                                                */
 
   inittime = MPI_Wtime();
 
   ierr=MPI_Allgather(sendbuff,buffsize,MPI_DOUBLE,
                      recvbuff[0],buffsize,MPI_DOUBLE,
                      MPI_COMM_WORLD);
 
   totaltime = MPI_Wtime() - inittime;
 
   /*===============================================================*/
   /* Affichage apres communication.                                */
 
   if ( taskid == 0 ){
     printf("\n");
     printf("##########################################################\n\n");
     printf("                --> APRES COMMUNICATION <-- \n");
   }
 
   /*===============================================================*/
   /* Calcul de la somme de chacun des vecteurs rassembles,         */
   /* et affichage ordonne a l'ecran par chaque tache.              */
   for(jtask=0;jtask<ntasks;jtask++){
     MPI_Barrier(MPI_COMM_WORLD);
     if ( taskid == jtask ){
       printf("\n");
       for(itask=0;itask<ntasks;itask++){
         buffsum=0.0;
         for(i=0;i<buffsize;i++){
           buffsum=buffsum+recvbuff[itask][i];
         }
         printf("Tache %d : Somme du vecteur recu par %d -> %e \n",
               taskid,itask,buffsum); 
       }              
     }
   }
 
   MPI_Barrier(MPI_COMM_WORLD);
 
   if(taskid==0){
     printf("\n");
     printf("##########################################################\n\n");
     printf(" Temps total de communication : %f secondes\n\n",totaltime);
     printf("##########################################################\n\n");
   }
 
   /*===============================================================*/
   /* Liberation de la memoire                                      */
     free(recvbuff[0]);
     free(recvbuff);
     free(sendbuff);
 
   /*===============================================================*/
   /* Finalisation de MPI                                           */
   MPI_Finalize();
}


Outils personnels
Espaces de noms

Variantes
Actions
Navigation
Ressources de Calcul Québec
Outils
Partager