Scatter

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_Scatter pour distribuer des données à l'ensemble des processus. Le processus 0 prépare (initialise) un ensemble de vecteurs réels de dimension buffsize (un pour chaque processus incluant le processus 0) et les place de façon contiguë en mémoire à l'intérieur d'un tableau. Ensuite, le processus 0 envoie chacun des vecteurs aux processus correspondants en utilisant la fonction MPI_Scatter.

Avant et après l'étape de communication, la somme de chacun des vecteurs est affichée à l'écran pour vérification. Cet exemple fait exactement la même chose que l'exemple 4 mais en utilisant des communications collectives. Vous pouvez comparer les performances de ces deux façons de faire! Vous verrez, il est beaucoup plus profitable d'utiliser des communications collectives quand c'est possible.

En Fortran

Fichier : scatter.f
!--------------------------------------------------------
!   
!            <----- Données sendbuff ------>
!   
!          ####################################
!          #      #      #      #      #      #
!        0 #  AA  #  BB  #  CC  #  DD  #  EE  #
!          #      #      #      #      #      #
!          ####################################
!     T    #      #      #      #      #      #
!        1 #      #      #      #      #      #
!     a    #      #      #      #      #      #
!          ####################################
!     c    #      #      #      #      #      #
!        2 #      #      #      #      #      #       AVANT
!     h    #      #      #      #      #      #
!          ####################################
!     e    #      #      #      #      #      #
!        3 #      #      #      #      #      #
!     s    #      #      #      #      #      #
!          ####################################
!          #      #      #      #      #      #
!        4 #      #      #      #      #      #
!          #      #      #      #      #      #
!          ####################################
!   
!          recvbuff
!   
!          ########
!          #      #
!        0 #  AA  #
!          #      #
!          ########
!     T    #      #
!        1 #  BB  #
!     a    #      #
!          ########
!     c    #      #
!        2 #  CC  #                                    APRÈS
!     h    #      #
!          ########
!     e    #      #
!        3 #  DD  #
!     s    #      #
!          ########
!          #      #
!        4 #  EE  #
!          #      #
!          ########
!
! Auteur : Carol Gauthier
!          Centre de calcul scientifique
!          Université de Sherbrooke
!
! Derniere révision : août 2004
!--------------------------------------------------------
Program Exemple_MPI
 
  include 'mpif.h'
  integer ierr,ntasks,taskid,itask,status(MPI_STATUS_SIZE)
  integer i,j,k,buffsize
  character argtmp*12
  real(8) inittime,recvtime,totaltime,rand,buffsum
 
  real(8),allocatable,dimension(:) :: buffsums
 
  real(8),allocatable,dimension(:,:) :: sendbuff
  real(8),allocatable,dimension(:) :: recvbuff
 
  !---------------------------------------------------------------
  ! Initialisation de MPI. Il est important de placer cet appel   
  ! au début du programme, immédiatement après les déclarations.  
  call MPI_INIT( ierr )
 
  !---------------------------------------------------------------
  ! Obtenir le nombre de processus MPI et le numéro d'identification
  ! du processus courant
  call MPI_COMM_SIZE(MPI_COMM_WORLD,ntasks,ierr)
  call MPI_COMM_RANK(MPI_COMM_WORLD,taskid,ierr)
 
  !---------------------------------------------------------------
  ! Dimension  du vecteur à 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 7"
    write(6,'(A)')
    write(6,'(A)')" Communication collective : MPI_Scatter"
    write(6,'(A)')
    write(6,'(A,I12)')" Dimension du vecteur :",buffsize
    write(6,'(A,I5)')" Nombre total de processus :",ntasks
    write(6,'(A)')
    write(6,'(A)')"##########################################################"
    write(6,'(A)')
    write(6,'(A)')"                --> AVANT COMMUNICATION <--"
    write(6,'(A)')
  endif
 
   !---------------------------------------------------------------
   ! Allocation de la mémoire
  allocate( sendbuff(0:buffsize-1,0:ntasks-1) )
  allocate( recvbuff(0:buffsize-1) )
  allocate( buffsums(0:ntasks-1) )
 
 
  if ( taskid.eq.0 )then
 
    !-----------------------------------------------------------------
    ! Initialisation des vecteurs ou tableaux.
    do itask=0,ntasks-1
      do i=0,buffsize-1
        sendbuff(i,itask)=rand();
      end do
    end do
 
    !-----------------------------------------------------------------
    ! Affichage avant communication.
    do itask=1,ntasks-1
      buffsum=0.0
      do i=0,buffsize-1
        buffsum=buffsum+sendbuff(i,itask)
      end do
      write(6,'(A,I3,A,I3,A,E14.8)')"Processus",taskid," : Somme du vecteur envoyé à ", & 
      &                              itask," -> ",buffsum
    end do
 
  end if
 
  !-----------------------------------------------------------------
  ! Communication
 
  inittime = MPI_Wtime()
 
  call MPI_Scatter(sendbuff,buffsize,MPI_REAL8, &
  &                recvbuff,buffsize,MPI_REAL8, &
  &                0,MPI_COMM_WORLD,ierr)
 
  totaltime = MPI_Wtime();
 
  !-----------------------------------------------------------------
  ! Affichage après communication.
  buffsum=0.0
  do i=0,buffsize-1
    buffsum=buffsum+recvbuff(i)
  end do
 
  call MPI_Gather(buffsum,1,MPI_REAL8,buffsums,1,MPI_REAL8, &
  &               0,MPI_COMM_WORLD,ierr)
 
  if(taskid.eq.0)then
    write(6,*)
    write(6,'(A)')"##########################################################"
    write(6,*)
    write(6,'(A)')"                --> APRÈS COMMUNICATION <--"
    write(6,*)
    do itask=1,ntasks-1
      write(6,'(A,I3,A,E14.8)')"Processus ",itask," : Somme du vecteur reçu = ",buffsums(itask)
    end do
    write(6,*)
    write(6,'(A)')"##########################################################"
    write(6,'(A,F5.2,A)')" Temps total de communication : ",totaltime," secondes"
    write(6,'(A)')"##########################################################"
    write(6,*)
  end if
 
  !-----------------------------------------------------------------
  ! Libération de la mémoire
  deallocate(sendbuff)
  deallocate(recvbuff)
  deallocate(buffsums)
 
  !-----------------------------------------------------------------
  ! Finalisation de MPI
 
  call MPI_FINALIZE( ierr )
end


En C

Fichier : scatter.c
/*--------------------------------------------------------
 
            <----- Données sendbuff ------>
 
          ####################################
          #      #      #      #      #      #
        0 #  AA  #  BB  #  CC  #  DD  #  EE  #
          #      #      #      #      #      #
          ####################################
     T    #      #      #      #      #      #
        1 #      #      #      #      #      #
     a    #      #      #      #      #      #
          ####################################
     c    #      #      #      #      #      #
        2 #      #      #      #      #      #       AVANT
     h    #      #      #      #      #      #
          ####################################
     e    #      #      #      #      #      #
        3 #      #      #      #      #      #
     s    #      #      #      #      #      #
          ####################################
          #      #      #      #      #      #
        4 #      #      #      #      #      #
          #      #      #      #      #      #
          ####################################
 
          recvbuff
 
          ########
          #      #
        0 #  AA  #
          #      #
          ########
     T    #      #
        1 #  BB  #
     a    #      #
          ########
     c    #      #
        2 #  CC  #                                    APRÈS
     h    #      #
          ########
     e    #      #
        3 #  DD  #
     s    #      #
          ########
          #      #
        4 #  EE  #
          #      #
          ########
 
 Auteur : Carol Gauthier
          Centre de calcul scientifique
          Université de Sherbrooke
 
 Dernière révision : 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)
{
   /*===============================================================*/
   /* Déclaration des variables                                     */
   int          taskid, ntasks;
   MPI_Status   status;
   int          ierr,i,j,itask;
   int	        buffsize;
   double       **sendbuff,*recvbuff,buffsum,buffsums[1024];
   double       inittime,totaltime,recvtime,recvtimes[1024];
 
   /*===============================================================*/
   /* Initialisation de MPI. Il est important de placer cet appel   */
   /* au début du programme, immédiatement après les declarations.   */
   MPI_Init(&argc, &argv);
 
   /*===============================================================*/
   /* Obtenir le nombre de processus MPI et le numéro d'identification */
   /* du processus courant taskid                                   */
   MPI_Comm_rank(MPI_COMM_WORLD,&taskid);
   MPI_Comm_size(MPI_COMM_WORLD,&ntasks);
 
   /*===============================================================*/
   /* Obtenir buffsize à 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 7 \n\n");
     printf(" Communication collective : MPI_Scatter \n\n");
     printf(" Dimension de chaque vecteur : %d\n",buffsize);
     printf(" Nombre total de processus : %d\n\n",ntasks);
     printf("##########################################################\n\n");
     printf("                --> AVANT COMMUNICATION <--\n\n");
   }
 
   /*=============================================================*/
   /* Allocation de la mémoire.                                   */ 
   recvbuff=(double *)malloc(sizeof(double)*buffsize);
   if ( taskid == 0 ){
     sendbuff=(double **)malloc(sizeof(double *)*ntasks);
     sendbuff[0]=(double *)malloc(sizeof(double)*ntasks*buffsize);
     for(i=1;i<ntasks;i++)sendbuff[i]=sendbuff[i-1]+buffsize;
   }
   else{
     sendbuff=(double **)malloc(sizeof(double *)*1);
     sendbuff[0]=(double *)malloc(sizeof(double)*1);
   }
 
 
   if ( taskid == 0 ){
 
     /*=============================================================*/
     /* Initialisation des vecteurs ou tableaux               */
     srand((unsigned)time( NULL ) + taskid);
     for(itask=0;itask<ntasks;itask++){
       for(i=0;i<buffsize;i++){
         sendbuff[itask][i]=(double)rand()/RAND_MAX;
       }
     }
 
     /*==============================================================*/
     /* Affichage avant communication.                               */
     for(itask=1;itask<ntasks;itask++){
       buffsum=0.0;
       for(i=0;i<buffsize;i++){
         buffsum=buffsum+sendbuff[itask][i];
       }
       printf("Processus %d : Somme du vecteur envoyé à %d -> %e \n",
               taskid,itask,buffsum);
 
     }  
     printf("\n");
 
   }    
 
   /*===============================================================*/
   /* Communication.                                                */
 
   inittime = MPI_Wtime();
 
   ierr=MPI_Scatter(sendbuff[0],buffsize,MPI_DOUBLE,
                    recvbuff,buffsize,MPI_DOUBLE,
                    0,MPI_COMM_WORLD);
 
   totaltime = MPI_Wtime() - inittime;
 
   /*===============================================================*/
   /* Affichage après communication.                                */
 
   buffsum=0.0;
   for(i=0 ; i<buffsize ; i++){
     buffsum=buffsum+recvbuff[i];
   }
 
   ierr=MPI_Gather(&buffsum,1,MPI_DOUBLE,
                   buffsums,1, MPI_DOUBLE,
                   0,MPI_COMM_WORLD);
 
   if(taskid==0){
     printf("##########################################################\n\n");
     printf("                --> APRÈS COMMUNICATION <-- \n\n");
     for(itask=1;itask<ntasks;itask++){
       printf("Processus %d : Somme du vecteur reçu : Somme= %e\n",
               itask,buffsums[itask]);
     }  
     printf("\n");
     printf("##########################################################\n\n");
     printf(" Temps total de communication : %f secondes\n\n",totaltime);  
     printf("##########################################################\n\n");
   }
 
   /*===============================================================*/
   /* Libération de la mémoire                                      */
   if ( taskid == 0 ){
     free(sendbuff[0]);
     free(sendbuff);
   }
   else{
     free(sendbuff[0]);
     free(sendbuff);
     free(recvbuff);
   }
 
   /*===============================================================*/
   /* Finalisation de MPI                                           */
   MPI_Finalize();
 
}


Outils personnels
Espaces de noms

Variantes
Actions
Navigation
Ressources de Calcul Québec
Outils
Partager