
- •Реферат
- •1. Mpi_Init, mpi_Finalize, “Hello, World” с анализом результата mpi_Init
- •---------------------------------------------------------------------------
- •2. Mpi_Send, mpi_Recv, анализ структуры mpi_Status
- •-----------------------------------------------------------------------------------------------------------------
- •3. Разрешение взаимной блокировки Send/Recv с помощью функции mpi_Sendrecv
- •------------------------------------------------------------------------
- •4. Пример использования mpi_Waitall, mpi_Waitany
- •--------------------------------------------------
- •5. Пример использования mpi_Bcast
- •--------------------------------------------------------------------------
- •6. Пример использования mpi_Gatherv и mpi_Scatterv
--------------------------------------------------
5. Пример использования mpi_Bcast
Broadcast - передача сообщения от одного процесса ко всем остальным процессам группы, включая его самого. Схематически broadcast можно изобразить следующим образом:
int MPI_Bcast(void *buff, int count, MPI_Datatype datatype, int root, MPI_Comm comm), где
buff - адрес начала буфера, хранящего передаваемое сообщение
count - количество передаваемых элементов
datatype - тип передаваемых элементов
root - номер корневого процесса, т.е. номер процесса от которого будет передаваться сообщение всем остальным процессам
comm - идентификатор группы
Пример. Каждый неrootпроцесс в буфереsbufхранит строку "I am not root", аroot-процесс кладет себе в буферsbufстроку "Hello from root" и рассылает ее при помощиMPI_Bcastвсем остальным. В результате, у каждого неrootпроцесса в буфере оказывается именно это сообщение.
# include <mpi.h>
# include <stdio.h>
# include <string.h>
int main(int argc, char** argv)
{
int numtasks, rank, root;
char sbuf[20];
strcpy(sbuf, "I am not root\0");
root = 1;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if(rank == root) strcpy(sbuf, "Hello from root\0");
MPI_Bcast(sbuf, 16, MPI_CHAR, root, MPI_COMM_WORLD);
if(rank == root) strcpy(sbuf, "I am root\0");
printf("I am %d. Message received: %s\n", rank, sbuf);
MPI_Finalize();
return 0;
}
Результат выполнения программы на 5 процессах:
I am 0. Message received: Hello from root
I am 3. Message received: Hello from root
I am 4. Message received: Hello from root
I am 1. Message received: I am root
I am 2. Message received: Hello from root
--------------------------------------------------------------------------
6. Пример использования mpi_Gatherv и mpi_Scatterv
Функция MPI_Gatherv:
int MPI_Gatherv (void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int *recvcnts, int *displs, MPI_Datatype recvtype, int root, MPI_Comm comm), где
sendbuf - Адрес, по которому находятся отправляемые данные
sendcount - Число отправляемых данных (в каждом процессе — свое)
sendtype - Тип отправляемых данных
recvcounts - Целочисленный массив размера, равного числу процессов в коммуникаторе; каждый элемент этого массива содержит число элементов, принимаемых от процесса с рангом, равным номеру этого элемента.
displs - Целочисленный массив размера, равного числу процессов в коммуникаторе. i-тый элемент определяет смещение (в элементах) относительно адреса recvbuf, по которому разместить данные, приходящие от процесса с рангом i. (имеет значение только в процессе с рангомroot)
recvtype - Тип принимаемых данных (имеет значение только в процессе с рангом root)
root - ранг процесса, который принимает данные.
comm-communicator(handle)
OUTrecvbuf- Адрес, по которому принимаются данные. (имеет значение только в процессе с рангомroot)
Пример. Здесь каждый процесс посылает 100 чисел типа int корневому процессу, но каждое множество (100 элементов) размещается с некоторым шагом (stride) относительно конца размещения предыдущего множества. Чтобы получить этот эффект нужно использовать MPI_GATHERV и аргумент displs. Полагаем, что stride > 100.
MPI_Comm comm;
int gsize,sendarray[100];
int root, *rbuf, stride;
int *displs,i,*rcounts;
...
MPI_Comm_size(comm, &gsize);
rbuf = (int *)malloc(gsize*stride*sizeof(int));
displs = (int *)malloc(gsize*sizeof(int));
rcounts = (int *)malloc(gsize*sizeof(int));
for (i=0; i<gsize; ++i) {
displs[i] = i*stride;
rcounts[i] = 100;
}
MPI_Gatherv(sendarray, 100, MPI_INT, rbuf, rcounts, displs,
MPI_INT, root, comm);
Функция MPI_Scatterv:
MPI_SCATTERV(sendbuf, sendcounts, displs, sendtype, recvbuf, recvcount, ecvtype, root, comm)
IN |
sendbuf |
адрес буфера посылки (альтернатива, используется только корневым процессом) |
|
IN |
sendcounts |
целочисленный массив (размера группы), определяющий число элементов, для отправки каждому процессу |
|
IN |
displs |
целочисленный массив (размера группы). Элемент i указывает смещение (относительно sendbuf, из которого берутся данные для процесса take the i) |
|
IN |
sendtype |
тип элементов посылающего буфера (дескриптор) |
|
OUT |
recvbuf |
адрес принимающего буфера (альтернатива) |
|
IN |
recvcount |
число элементов в посылающем буфере (целое) |
|
IN |
recvtype |
тип данных элементов принимающего буфера (дескриптор) |
|
IN |
root |
номер посылающего процесса (целое) |
|
IN |
comm |
коммуникатор (дескриптор) |
|
Пример.Корневой процесс рассылает множества из 100 чисел типа int остальным процессам, но множества размещены в посылающем буфере с шагом stride, поэтому нужно использовать MPI_Scatterv. Полагаем stride > 100.
MPI_Comm comm;
int gsize,*sendbuf;
int root, rbuf[100], i, *displs, *scounts;
...
MPI_Comm_size(comm, &gsize);
sendbuf = (int*)malloc(gsize*stride*sizeof(int));
...
displs = (int*)malloc(gsize*sizeof(int));
scounts = (int*)malloc(gsize*sizeof(int));
for (i=0; i<gsize; ++i) {
displs[i] = i*stride;
scounts[i] = 100;
}
MPI_Scatterv(sendbuf, scounts, displs, MPI_INT, rbuf, 100,
MPI_INT, root, comm);