Вперед: 4.4.3. Функции распределения блоков данных по всем процессам группы
Назад: 4.4.1. Обзор коллективных операций
К содержанию: Оглавление


4.4.2. Функции сбора блоков данных от всех процессов группы

Семейство функций сбора блоков данных от всех процессов группы состоит из четырех подпрограмм: MPI_Gather, MPI_Allgather, MPI_Gatherv, MPI_Allgatherv. Каждая из указанных подпрограмм расширяет функциональные возможности предыдущих.

Функция MPI_Gather производит сборку блоков данных, посылаемых всеми процессами группы, в один массив процесса с номером root. Длина блоков предполагается одинаковой. Объединение происходит в порядке увеличения номеров процессов-отправителей. То есть данные, посланные процессом i из своего буфера sendbuf, помещаются в i-ю порцию буфера recvbuf процесса root. Длина массива, в который собираются данные, должна быть достаточной для их размещения.

С:
int MPI_Gather(void* sendbuf, int sendcount, MPI_Datatype sendtype,
void* recvbuf, int recvcount, MPI_Datatype recvtype,
int root, MPI_Comm comm)
FORTRAN:
MPI_GATHER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF,
RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR)
<type> SENDBUF(*), RECVBUF(*)
INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR
IN sendbuf - адрес начала размещения посылаемых данных;
IN sendcount - число посылаемых элементов;
IN sendtype - тип посылаемых элементов;
OUT recvbuf - адрес начала буфера приема (используется только в процессе-получателе root);
IN recvcount - число элементов, получаемых от каждого процесса (используется только в процессе-получателе root);
IN recvtype - тип получаемых элементов;
IN root - номер процесса-получателя;
IN comm - коммуникатор.

Тип посылаемых элементов sendtype должен совпадать с типом recvtype получаемых элементов, а число sendcount должно равняться числу recvcount. То есть, recvcount в вызове из процесса root - это число собираемых от каждого процесса элементов, а не общее количество собранных элементов. Графическая интерпретация операции Gather представлена на Рис. 4.2.

Графическая интерпретация операции Gather.

Рис. 4.2. Графическая интерпретация операции Gather.

Функция MPI_Allgather выполняется так же, как MPI_Gather, но получателями являются все процессы группы. Данные, посланные процессом i из своего буфера sendbuf, помещаются в i-ю порцию буфера recvbuf каждого процесса. После завершения операции содержимое буферов приема recvbuf у всех процессов одинаково.

C:
int MPI_Allgather(void* sendbuf, int sendcount, MPI_Datatype sendtype,
void* recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm)
FORTRAN:
MPI_ALLGATHER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF,
RECVCOUNT, RECVTYPE, COMM, IERROR)
<type> SENDBUF(*), RECVBUF(*)
INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, COMM, IERROR
IN sendbuf - адрес начала буфера посылки;
IN sendcount - число посылаемых элементов;
IN sendtype - тип посылаемых элементов;
OUT recvbuf - адрес начала буфера приема;
IN recvcount - число элементов, получаемых от каждого процесса;
IN recvtype - тип получаемых элементов;
IN comm - коммуникатор.

Графическая интерпретация операции Allgater представлена на рис 4.3. На этой схеме ось Y образуют процессы группы, а ось X блоки данных.

Графическая интерпретация операции Аllgather.

Рис 4.3. Графическая интерпретация операции Аllgather.

Функция MPI_Gatherv позволяет собирать блоки с разным числом элементов от каждого процесса, так как количество элементов, принимаемых от каждого процесса, задается индивидуально с помощью массива recvcounts. Эта функция обеспечивает также большую гибкость при размещении данных в процессе-получателе, благодаря введению в качестве параметра массива смещений displs.

C:
int MPI_Gatherv(void* sendbuf, int sendcount, MPI_Datatype sendtype,
void* rbuf, int *recvcounts, int *displs, MPI_Datatype recvtype,
int root, MPI_Comm comm)
FORTRAN:
MPI_GATHERV(SENDBUF, SENDCOUNT, SENDTYPE, RBUF,
RECVCOUNTS, DISPLS, RECVTYPE, ROOT, COMM, IERROR)
<type> SENDBUF(*), RBUF(*)
INTEGER SENDCOUNT, SENDTYPE, RECVCOUNTS(*), DISPLS(*),
RECVTYPE, ROOT, COMM, IERROR
IN sendbuf - адрес начала буфера передачи;
IN sendcount - число посылаемых элементов;
IN sendtype - тип посылаемых элементов;
OUT rbuf - адрес начала буфера приема;<
IN recvcounts - целочисленный массив (размер равен числу процессов в группе), i-й элемент которого определяет число элементов, которое должно быть получено от процесса i;
IN displs - целочисленный массив (размер равен числу процессов в группе), i-ое значение определяет смещение i-го блока данных относительно начала rbuf;
IN recvtype - тип получаемых элементов;
IN root - номер процесса-получателя;
IN comm - коммуникатор.

Сообщения помещаются в буфер приема процесса root в соответствии с номерами посылающих процессов, а именно, данные, посланные процессом i, размещаются в адресном пространстве процесса root, начиная с адреса rbuf + displs[i]. Графическая интерпретация операции Gatherv представлена на рис. 4.4.

Графическая интерпретация операции Gatherv.

Рис. 4.4. Графическая интерпретация операции Gatherv.

Функция MPI_Allgatherv является аналогом функции MPI_Gatherv, но сборка выполняется всеми процессами группы. Поэтому в списке параметров отсутствует параметр root.

C:
int MPI_Allgatherv(void* sendbuf, int sendcount, MPI_Datatype sendtype,
void* rbuf, int *recvcounts, int *displs,
MPI_Datatype recvtype, MPI_Comm comm)
FORTRAN:
MPI_ALLGATHERV(SENDBUF, SENDCOUNT, SENDTYPE, RBUF, RECVCOUNTS,
DISPLS, RECVTYPE, COMM, IERROR)
<type> SENDBUF(*), RBUF(*)
INTEGER SENDCOUNT, SENDTYPE, RECVCOUNTS(*), DISPLS(*),
RECVTYPE, COMM, IERROR
IN sendbuf - адрес начала буфера передачи;
IN sendcount - число посылаемых элементов;
IN sendtype - тип посылаемых элементов;
OUT rbuf - адрес начала буфера приема;
IN recvcounts - целочисленный массив (размер равен числу процессов в группе), содержащий число элементов, которое должно быть получено от каждого процесса;
IN displs - целочисленный массив (размер равен числу процессов в группе), i-ое значение определяет смещение относительно начала rbuf i-го блока данных;
IN recvtype - тип получаемых элементов;
IN comm - коммуникатор.

Приведем пример программы на использование функций сбора данных.

Программа gather.c

#include <stdio.h>
#include "mpi.h"
int main(int argc,char *argv[])
{
int iam,nproc;
int nl,len,i,j,k;
int *iar,*iar_all;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&iam);
MPI_Comm_size(MPI_COMM_WORLD,&nproc);

if (iam == 0) nl=10;
MPI_Bcast(&nl,1,MPI_INT,0,MPI_COMM_WORLD);

len = nl * nproc;

iar = malloc(nl * sizeof(int));
iar_all = malloc(len * sizeof(int));

for( i = 0; i < nl; i++ ){
iar[i] = iam * nl + i+1;
 }
MPI_Gather(iar,nl,MPI_INT,iar_all,nl,MPI_INT,0,MPI_COMM_WORLD);
 if ( iam == 0 ){
  k =0;
  for( i = 0; i < nproc; i++){
   for( j = 0; j < nl; j++){
   printf("%3d ",iar_all[k]);
   k++;
   }
  printf("\n");
  }
 }
MPI_Finalize();
return 0;
}

Программа gather.f

program gather
   include 'mpif.h'
   integer i,j,IAM,NPROC,ierr,len,nl
   integer, dimension(:), allocatable :: iar, iar_all

   CALL MPI_INIT(ierr)
   CALL MPI_COMM_SIZE(MPI_COMM_WORLD,NPROC,ierr)
   CALL MPI_COMM_RANK(MPI_COMM_WORLD,IAM,ierr)

   if(IAM.EQ.0) then 
   nl = 10
   end if
   CALL MPI_Bcast(nl,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr)
   len = nl*NPROC
   allocate ( iar(1:nl))
   allocate ( iar_all(1:len))

   do i = 1,nl
   iar(i) = IAM*nl + i
   end do
   CALL MPI_Gather(iar, nl, MPI_INTEGER, iar_all, nl, 
   * 	MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)

   if (IAM.EQ.0 ) write (*,10) iar_all
 10 format(2x, 10I4)
   CALL MPI_FINALIZE(ierr)
   END


Вперед: 4.4.3. Функции распределения блоков данных по всем процессам группы
Назад: 4.4.1. Обзор коллективных операций
К содержанию: Оглавление