Scatterv

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_Scatterv. Similaire à l'exemple 7, sauf que seules des portions de vecteurs sont envoyées aux autres processus. Cette fonctionnalité permet de mieux contrôler la quantité de données transférées et d'ainsi limiter le temps de communication.

Le processus 0 prépare 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 sendbuff. Ensuite, le processus 0 envoie une portion de vecteurs à chacun des processus en utilisant la fonction MPI_Scatterv.

Avant l'étape de communication, la somme de chaque portion de vecteur est affichée à l'écran par le processus 0. Après l'étape de communication, chaque processus calcule la somme de la portion de vecteur reçue, et ces sommes sont rapatriées, avec les temps de réception, vers le processus 0 en utilisant la fonction MPI_Gather, pour affichage à l'écran.

En Fortran

Fichier : scatterv.f
!--------------------------------------------------------
!   
!            <----- Données sendbuff ------>
!   
!          ####################################
!          #      #      #      #      #      #
!        0 # ABCD # EFGH # IJKL # MNOP # QRST #
!          #      #      #      #      #      #
!          ####################################
!     T    #      #      #      #      #      #
!        1 #      #      #      #      #      #
!     a    #      #      #      #      #      #
!          ####################################
!     c    #      #      #      #      #      #
!        2 #      #      #      #      #      #       AVANT
!     h    #      #      #      #      #      #
!          ####################################
!     e    #      #      #      #      #      #
!        3 #      #      #      #      #      #
!     s    #      #      #      #      #      #
!          ####################################
!          #      #      #      #      #      #
!        4 #      #      #      #      #      #
!          #      #      #      #      #      #
!          ####################################
!   
!          recvbuff
!   
!          ########
!          #      #
!        0 # AB   #
!          #      #
!          ########
!     T    #      #
!        1 # EFG  #
!     a    #      #
!          ########
!     c    #      #
!        2 # I    #                                   APRÈS
!     h    #      #
!          ########
!     e    #      #
!        3 # MNOP #
!     s    #      #
!          ########
!          #      #
!        4 # QRS  #
!          #      #
!          ########
!
! Auteur : Carol Gauthier
!          Centre de calcul scientifique
!          Université de Sherbrooke
!
! Dernière revision : août 2004
!--------------------------------------------------------
 
Program Exemple_MPI
 
  include 'mpif.h'
  integer ierr,ntasks,taskid,itask,status(MPI_STATUS_SIZE)
  integer i,j,k,buffsize,displs(0:2048),sendcounts(0:2048),recvcount
  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 8"
    write(6,'(A)')
    write(6,'(A)')" Communication collective : MPI_Scatterv"
    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 et tableaux.
    do itask=0,ntasks-1
      displs(itask)=itask*buffsize
      sendcounts(itask)=buffsize/(itask+1)
      do i=0,sendcounts(itask)-1
        sendbuff(i,itask)=rand()
      end do
    end do
 
   !-----------------------------------------------------------------
   ! Affichage avant communication.
   do itask=1,ntasks-1
      buffsum=0.0
      do i=0,sendcounts(itask)-1
        buffsum=buffsum+sendbuff(i,itask)
      end do
      write(6,'(A,I3,A,I3,A,E14.8,A,I9)')"Processus",taskid," : Vecteur envoyé à ", & 
      &                              itask," : somme= ",buffsum," taille=",sendcounts(itask)
   end do
 
  end if
 
  !-----------------------------------------------------------------
  ! Taille du vecteur reçu
  recvcount=buffsize/(taskid+1)
 
   !-----------------------------------------------------------------
   ! Communication
 
   inittime = MPI_Wtime()
 
   call MPI_Scatterv(sendbuff,sendcounts,displs,MPI_REAL8, &
   &                 recvbuff,recvcount,MPI_REAL8, &
   &                 0,MPI_COMM_WORLD,ierr)
 
   totaltime = MPI_Wtime()
 
   !-----------------------------------------------------------------
   ! Affichage après communication.
 
   buffsum=0.0
   do i=0,recvcount-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 : scatterv.c
/*--------------------------------------------------------
 
            <----- Données sendbuff ------>
 
          ####################################
          #      #      #      #      #      #
        0 # ABCD # EFGH # IJKL # MNOP # QRST #
          #      #      #      #      #      #
          ####################################
     T    #      #      #      #      #      #
        1 #      #      #      #      #      #
     a    #      #      #      #      #      #
          ####################################
     c    #      #      #      #      #      #
        2 #      #      #      #      #      #       AVANT
     h    #      #      #      #      #      #
          ####################################
     e    #      #      #      #      #      #
        3 #      #      #      #      #      #
     s    #      #      #      #      #      #
          ####################################
          #      #      #      #      #      #
        4 #      #      #      #      #      #
          #      #      #      #      #      #
          ####################################
 
          recvbuff
 
          ########
          #      #
        0 # AB   #
          #      #
          ########
     T    #      #
        1 # EFG  #
     a    #      #
          ########
     c    #      #
        2 # I    #                                   APRÈS
     h    #      #
          ########
     e    #      #
        3 # MNOP #
     s    #      #
          ########
          #      #
        4 # QRS  #
          #      #
          ########
 
 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,sendcounts[2048],displs[2048],recvcount;
   double       **sendbuff,*recvbuff,buffsum,buffsums[2048];
   double       inittime,totaltime,recvtime,recvtimes[2048];
 
   /*===============================================================*/
   /* Initialisation de MPI. Il est important de placer cet appel   */
   /* au début du programme, immédiatement apres les déclarations   */
   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 8 \n\n");
     printf(" Communication collective : MPI_Scatterv \n\n");
     printf(" Dimension de chaque vecteur à transférer : %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 et tableaux                     */
 
     srand((unsigned)time( NULL ) + taskid);
     for(itask=0;itask<ntasks;itask++){
       displs[itask]=itask*buffsize;
       sendcounts[itask]=buffsize/(itask+1);
       for(i=0;i<sendcounts[itask];i++){
         sendbuff[itask][i]=(double)rand()/RAND_MAX;
       }
     }
 
     /*==============================================================*/
     /* Affichage avant communication.                               */
     for(itask=0;itask<ntasks;itask++){
       buffsum=0.0;
       for(i=0;i<sendcounts[itask];i++){
         buffsum=buffsum+sendbuff[itask][i];
       }
       printf("Processus %d : Vecteur envoyé à %d : somme=%e taille= %d\n",
               taskid,itask,buffsum,sendcounts[itask]);
 
     }  
 
   }
 
   /*=================================================================*/
   /* Taille du vecteur reçu                                          */
   recvcount=buffsize/(taskid+1);
 
   /*===============================================================*/
   /* Communication.                                                */
 
   inittime = MPI_Wtime();
 
   ierr=MPI_Scatterv(sendbuff[0],sendcounts,displs,MPI_DOUBLE,
                     recvbuff,recvcount,MPI_DOUBLE,
                     0,MPI_COMM_WORLD);
 
   totaltime = MPI_Wtime() - inittime;
 
   /*===============================================================*/
   /* Affichage après communication.                                */
 
   buffsum=0.0;
   for(i=0 ; i<recvcount ; 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");
     printf("##########################################################\n\n");
     printf("                --> APRÈS COMMUNICATION <-- \n\n");
     for(itask=0;itask<ntasks;itask++){
       printf("Processus %d : Somme du vecteur reçu : %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