MPI Reduce

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

Cet exemple illustre l'utilisation de la fonction MPI_Reduce.

Chaque processus prépare (initialise) un vecteur de réels sendbuff de dimension buffsize. La fonction MPI_Reduce effectue une opération mathématique entre les je éléments de sendbuff de tous les processus et place le résultat dans le je élément de recvbuff du processus racine (0 dans le cas présent), et ce, pour tous les éléments de sendbuff. L'opération mathématique effectuée peut être une somme, un produit, une recherche de maximum ou de minimum, etc.

De façon similaire, la fonction MPI_Allreduce effectue le même travail, mais en distribuant les résultats (recvbuff) sur tous les processus.

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 : reduce.f
!--------------------------------------------------------
!   
!            <--- sendbuff ---->
!           
!     T     *********************
!         0 * A0 * B0 * .. * Z0 *
!     a     *********************
!         1 * A1 * B1 * .. * Z1 *
!     c     *********************
!         2 * A2 * B2 * .. * Z2 *
!     h     *********************
!         3 * A3 * B3 * .. * Z3 *
!     e     *********************
!         4 * A4 * B4 * .. * Z4 *
!     s     *********************
!          
!            <--- recvbuff ---->
!           
!     T     **************************************************
!         0 * A0+A1+..+A4 * B0+B1+..+B4 *  ..  * Z0+Z1+..+Z4 *
!     a     **************************************************
!         1 *             *             *  ..  *             *
!     c     **************************************************
!         2 *             *             *  ..  *             *
!     h     **************************************************
!         3 *             *             *  ..  *             *
!     e     **************************************************
!         4 *             *             *  ..  *             *
!     s     **************************************************
!          
! 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,totalsum
 
  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 12"
    write(6,'(A)')
    write(6,'(A)')" Communication collective : MPI_Reduce"
    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 memoire 
  allocate( sendbuff(0:buffsize-1) )
  allocate( recvbuff(0:buffsize-1) )
 
  !-----------------------------------------------------------------
  ! Initialisation des vecteurs 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)')"Processus",taskid," : somme des éléments de sendbuff= ",buffsum
 
  call MPI_Barrier(MPI_COMM_WORLD,ierr)
 
  call MPI_Reduce(buffsum,totalsum,1,MPI_REAL8,MPI_SUM,0,MPI_COMM_WORLD,ierr)
 
if(taskid.eq.0)then
    write(6,*)"                                         ============="
    write(6,'(A,E14.8)')"                                   TOTAL : ",totalsum
  end if
 
  !-----------------------------------------------------------------
  ! Communication
 
  inittime = MPI_Wtime()
 
  call MPI_Reduce(sendbuff,recvbuff,buffsize,MPI_REAL8,MPI_SUM, &
  &               0,MPI_COMM_WORLD,ierr)
 
  totaltime = MPI_Wtime()
 
  !-----------------------------------------------------------------
  ! Affichage après communication.
  if(taskid.eq.0)then
    write(6,*)
    write(6,'(A)')"##########################################################"
    write(6,*)
    write(6,'(A)')"                --> APRÈS COMMUNICATION <--"
    write(6,*)
    buffsum=0.0
    do i=0,buffsize-1
      buffsum=buffsum+recvbuff(i)
    end do
    write(6,'(A,I3,A,E14.8)')"Tache ",taskid," : Somme des éléments de recvbuff ",buffsum
    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)
 
  !-----------------------------------------------------------------
  ! Finalisation de MPI
 
  call MPI_FINALIZE( ierr )
 
end


En C

Fichier : reduce.c
/*--------------------------------------------------------
 
            <--- sendbuff ---->
 
     T     *********************
         0 * A0 * B0 * .. * Z0 *
     a     *********************
         1 * A1 * B1 * .. * Z1 *
     c     *********************
         2 * A2 * B2 * .. * Z2 *
     h     *********************
         3 * A3 * B3 * .. * Z3 *
     e     *********************
         4 * A4 * B4 * .. * Z4 *
     s     *********************
 
            <--- recvbuff ---->
 
     T     **************************************************
         0 * A0+A1+..+A4 * B0+B1+..+B4 *  ..  * Z0+Z1+..+Z4 *
     a     **************************************************
         1 *             *             *  ..  *             *
     c     **************************************************
         2 *             *             *  ..  *             *
     h     **************************************************
         3 *             *             *  ..  *             *
     e     **************************************************
         4 *             *             *  ..  *             *
     s     **************************************************
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,totalsum;
   double       inittime,totaltime;
 
   /*===============================================================*/
   /* Initialisation de MPI. Il est important de placer cet appel   */
   /* au début du programme, immédiatement après 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 12 \n\n");
     printf("  Communication collective : MPI_Reduce \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.                                   */ 
   sendbuff=(double *)malloc(sizeof(double)*buffsize);
   recvbuff=(double *)malloc(sizeof(double)*buffsize);
 
   /*=============================================================*/
   /* Initialisation des vecteurs 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(" Processus %d : somme des éléments de sendbuff = %e \n",taskid,buffsum);
 
   MPI_Barrier(MPI_COMM_WORLD);
 
   ierr=MPI_Reduce(&buffsum,&totalsum,1,MPI_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD);
   if(taskid==0){
     printf("                                            =============\n",taskid,totalsum);
     printf("                                     TOTAL : %e \n\n",totalsum);   
   }
 
   /*===============================================================*/
   /* Communication.                                                */
 
   inittime = MPI_Wtime();
 
   ierr=MPI_Reduce(sendbuff,recvbuff,buffsize,MPI_DOUBLE,MPI_SUM,
                   0,MPI_COMM_WORLD);
 
   totaltime = MPI_Wtime() - inittime;
 
   /*===============================================================*/
   /* Affichage après communication.                                */
   if ( taskid == 0 ){
     printf("##########################################################\n\n");
     printf("                --> APRÈS COMMUNICATION <-- \n\n");
     buffsum=0.0;
     for(i=0;i<buffsize;i++){
       buffsum=buffsum+recvbuff[i];
     }
     printf(" Processus %d : somme des éléments de recvbuff -> %e \n",taskid,buffsum);
     printf("\n");
     printf("##########################################################\n\n");
     printf(" Temps total de communication : %f secondes\n\n",totaltime);  
     printf("##########################################################\n\n");
   }
 
   /*===============================================================*/
   /* Libération de la mémoire                                      */
   free(recvbuff);
   free(sendbuff);
 
   /*===============================================================*/
   /* Finalisation de MPI                                           */
   MPI_Finalize();
}


Outils personnels
Espaces de noms

Variantes
Actions
Navigation
Ressources de Calcul Québec
Outils
Partager