Send-Recv

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

Cet exemple illustre l'utilisation des fonctions MPI_Send et MPI_Recv.

Le processus 0 prépare (alloue la mémoire et initialise) un ensemble de vecteurs de réels de dimension buffsize (un pour chaque processus incluant le processus 0). Ensuite, le processus 0 envoie à tour de rôle chacun des vecteurs aux processus correspondants. Avant l'étape de communication, la somme de chacun des vecteurs est affichée à l'écran par le processus 0. Après l'étape de communication, chaque processus calcule la somme du vecteur reçu, 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. Cet exemple ne fait qu'illustrer l'utilisation de MPI_Send et MPI_Recv, il existe une manière plus efficace d'effectuer le même travail en utilisant la fonction MPI_Scatter, comme le démontre l'exemple 7. Il est d'ailleure fortement conseillé d'utiliser les fonctions de communication collective partout où cela est possible.

En Fortran

Fichier : send_recv.f
! --------------------------------------------------------
!   
!            <---------- Données ----------->
!   
!          ####################################
!          #      #      #      #      #      #
!        0 #  AA  #  BB  #  CC  #  DD  #  EE  #
!          #      #      #      #      #      #
!          ####################################
!     T    #      #      #      #      #      #
!        1 #      #      #      #      #      #
!     a    #      #      #      #      #      #
!          ####################################
!     c    #      #      #      #      #      #
!        2 #      #      #      #      #      #       AVANT
!     h    #      #      #      #      #      #
!          ####################################
!     e    #      #      #      #      #      #
!        3 #      #      #      #      #      #
!     s    #      #      #      #      #      #
!          ####################################
!          #      #      #      #      #      #
!        4 #      #      #      #      #      #
!          #      #      #      #      #      #
!          ####################################
!   
!            <---------- Données ----------->
!   
!          ####################################
!          #      #      #      #      #      #
!        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 : 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(:) :: recvtimes
  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 4"
    write(6,'(A)')
    write(6,'(A)')" Communication point à point : MPI_Send  MPI_Recv"
    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
 
 
  if ( taskid.eq.0 )then
 
    !---------------------------------------------------------------
    ! Allocation de la mémoire
    allocate( sendbuff(0:buffsize-1,0:ntasks-1) )
    allocate( recvbuff(0:buffsize-1) )
    allocate( recvtimes(0:ntasks-1) )
    allocate( buffsums(0:ntasks-1) )
 
    !-----------------------------------------------------------------
    ! Initialisation des vecteurs et 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
 
  else
 
    !---------------------------------------------------------------
    ! Allocation de la mémoire 
    allocate( recvbuff(0:buffsize-1) )
    allocate( recvtimes(0:ntasks-1) )
    allocate( buffsums(0:ntasks-1) )
 
  end if
 
  !-----------------------------------------------------------------
  ! Communication
 
  inittime = MPI_Wtime();
 
  if ( taskid.eq.0 ) then
 
    do itask=1,ntasks-1
       call MPI_Send(sendbuff(0,itask),buffsize,MPI_REAL8, &
       &             itask,0,MPI_COMM_WORLD,ierr)  
    end do
 
  else
 
    call MPI_Recv(recvbuff,buffsize,MPI_REAL8, &
    &             0,MPI_ANY_TAG,MPI_COMM_WORLD,status,ierr);
 
    recvtime = MPI_Wtime();
 
    buffsum=0.0
    do i=0,buffsize-1
      buffsum=buffsum+recvbuff(i)
    end do
 
  end if
 
  call MPI_Barrier(MPI_COMM_WORLD,ierr)
 
  totaltime=MPI_Wtime()
 
  !-----------------------------------------------------------------
  ! Affichage après communication.
 
  call MPI_Gather(recvtime,1,MPI_REAL8,recvtimes,1,MPI_REAL8, &
  &               0,MPI_COMM_WORLD,ierr)
 
  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,F5.2,A,e14.8)')"Processus ",itask," : Vecteur reçu à",recvtimes(itask), &
      &                             " secondes : Somme = ",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
 
  call MPI_Barrier(MPI_COMM_WORLD,ierr)
 
 
  !-----------------------------------------------------------------
  ! Libération de la mémoire
  if(taskid.eq.0) deallocate(sendbuff)
  deallocate(recvbuff)
  deallocate(recvtimes)
  deallocate(buffsums)
 
  !-----------------------------------------------------------------
  ! Finalisation de MPI
  call MPI_FINALIZE( ierr )
 
end


En C

Fichier : send_recv.c
/*--------------------------------------------------------
 
            <---------- Données ----------->
 
          ####################################
          #      #      #      #      #      #
        0 #  AA  #  BB  #  CC  #  DD  #  EE  #
          #      #      #      #      #      #
          ####################################
     T    #      #      #      #      #      #
        1 #      #      #      #      #      #
     a    #      #      #      #      #      #
          ####################################
     c    #      #      #      #      #      #
        2 #      #      #      #      #      #       AVANT
     h    #      #      #      #      #      #
          ####################################
     e    #      #      #      #      #      #
        3 #      #      #      #      #      #
     s    #      #      #      #      #      #
          ####################################
          #      #      #      #      #      #
        4 #      #      #      #      #      #
          #      #      #      #      #      #
          ####################################
 
            <---------- Données ----------->
 
          ####################################
          #      #      #      #      #      #
        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 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 4 \n\n");
     printf(" Communication point à point : MPI_Send MPI_Recv \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");
   }
 
 
   if ( taskid == 0 ){
     /*=============================================================*/
     /* Allocation de la mémoire.                                   */ 
     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;
 
     /*=============================================================*/
     /* Initialisation des vecteurs et 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);       
     }  
 
   }
   else{
 
     /*=============================================================*/
     /* Allocation de la mémoire.                                   */ 
     recvbuff=(double *)malloc(sizeof(double)*buffsize);
 
   }
 
   /*===============================================================*/
   /* Communication.                                                */
 
   inittime = MPI_Wtime();
 
   if ( taskid == 0 ){
 
     for(itask=1 ; itask<ntasks ; itask++){
 
       ierr = MPI_Send(sendbuff[itask],
                       buffsize,
                       MPI_DOUBLE,
	               itask,
	               0,
                       MPI_COMM_WORLD);
     } 
 
   }
   else{
 
     ierr = MPI_Recv(recvbuff,
                     buffsize,
                     MPI_DOUBLE,
                     0,
                     MPI_ANY_TAG,
                     MPI_COMM_WORLD,
                     &status);
 
     recvtime = MPI_Wtime();
 
     buffsum=0.0;
     for(i=0 ; i<buffsize ; i++){
       buffsum=buffsum+recvbuff[i];
     }
 
   }
 
   MPI_Barrier(MPI_COMM_WORLD);
 
   totaltime = MPI_Wtime() - inittime;
 
   /*===============================================================*/
   /* Affichage après communication.                                */
 
   ierr=MPI_Gather(&recvtime,1,MPI_DOUBLE,
                   recvtimes,1, MPI_DOUBLE,
                   0,MPI_COMM_WORLD);
 
   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=1;itask<ntasks;itask++){
       printf("Processus %d : Buffer reçu à %f secondes : Somme= %e\n",
               itask,recvtimes[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(recvbuff);
   }
 
   /*===============================================================*/
   /* Finalisation de MPI                                           */
   MPI_Finalize();
}


Outils personnels
Espaces de noms

Variantes
Actions
Navigation
Ressources de Calcul Québec
Outils
Partager