next up previous contents
Next: Рассылка Up: Сборка данных Previous: Сборка данных   Contents

Примеры использования функций MPI_GATHER, MPI_GATHERV

Пример 4.2 Сбор 100 целых чисел с каждого процесса группы в корневой процесс (рис. 4.2).

MPI_Comm comm; int gsize, sendarray[100]; int root, *rbuf; ... MPI_Comm_size(comm, &gsize); rbuf = (int *)malloc(gsize*100*sizeof(int)); MPI_Gather(sendarray, 100, MPI_INT, rbuf, 100, MPI_INT, root, comm);

Пример 4.3 Предыдущий пример модифицирован - только корневой процесс выделяет память для буфера приема.

MPI_Comm comm; int gsize,sendarray[100]; int root, myrank, *rbuf; ... MPI_Comm_rank(comm, myrank); if (myrank == root) { MPI_Comm_size(comm, &gsize); rbuf = (int *)malloc(gsize*100*sizeof(int)); } MPI_Gather(sendarray, 100, MPI_INT, rbuf, 100, MPI_INT, root, comm);

Пример 4.4. Программа делает то же, что и в предыдущем примере, но использует производные типы данных. Отметим, что тип не может быть полным множеством gsize*100 чисел типа int, поскольку соответствующие типы определены попарно между каждым процессом, участвующим в сборе данных, и корневым процессом.

MPI_Comm comm; int gsize,sendarray[100]; int root, *rbuf; MPI_Datatype rtype; ... MPI_Comm_size(comm, &gsize); MPI_Type_contiguous(100, MPI_INT, &rtype); MPI_Type_commit(&rtype); rbuf = (int *)malloc(gsize*100*sizeof(int)); MPI_Gather(sendarray, 100, MPI_INT, rbuf, 1, rtype, root, comm);

Пример 4.5 Здесь каждый процесс посылает 100 чисел типа int корневому процессу, но каждое множество (100 элементов) размещается с некоторым шагом (stride) относительно конца размещения предыдущего множества. Чтобы получить этот эффект нужно использовать MPI_GATHERV и аргумент displs. Полагаем, что stride > 100 (рис. 4.3).

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);

Отметим, что программа неверна, если stride < 100.

\includegraphics[width=5.77in,height=2.82in]{Ch4figure3.eps}

Пример 4.6. Со стороны процесса-получателя пример такой же, как и 4.5, но посылается 100 чисел типа int из 0-го столбца C-массива 100x150 чисел типа int (рис. 4.4).

MPI_Comm comm; int gsize,sendarray[100][150]; int root, *rbuf, stride; MPI_Datatype stype; 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; } /* Create datatype for 1 column of array */ MPI_Type_vector(100, 1, 150, MPI\_INT, &stype); MPI_Type_commit(&stype); MPI_Gatherv(sendarray, 1, stype, rbuf, rcounts, displs, MPI_INT, root, comm);

\includegraphics[width=5.83in,height=2.99in]{Ch4figure4.eps}

Пример 4.7 Процесс i посылает (100-i) чисел типа int из i-ого столбца C - массива 100x150 чисел типа int на языке Си (рис.4.5)

MPI_Comm comm; int gsize,sendarray[100][150],*sptr; int root, *rbuf, stride, myrank; MPI_Datatype stype; int *displs,i,*rcounts; ... MPI_Comm_size(comm, &gsize); MPI_Comm_rank(comm, &myrank); 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-i; /* отличие от предыдущего примера */ } /* создается тип данных для посылаемого столбца */ MPI_Type_vector(100-myrank, 1, 150, MPI_INT, &stype); MPI_Type_commit(&stype); /* sptr есть адрес начала столбца "myrank" */ sptr = &sendarray[0][myrank]; MPI_Gatherv(sptr, 1, stype, rbuf, rcounts, displs, MPI_INT, root, comm);

Отметим, что из каждого процесса получено различное количество данных.

\includegraphics[width=5.33in,height=2.84in]{Ch4figure5.eps}

Пример 4.8. Пример такой же, как и 4.7, но содержит отличие на передающей стороне. Создается тип данных с корректным страйдом на передающей стороне для чтения столбца массива на языке Си. Подобная вещь была сделана в примере 3.33, раздел 3.12.7.

MPI_Comm comm; int gsize, sendarray[100][150], *sptr; int root, *rbuf, stride, myrank, disp[2], blocklen[2]; MPI_Datatype stype,type[2]; int *displs,i,*rcounts; ... MPI_Comm_size(comm, &gsize); MPI_Comm_rank(comm, &myrank); 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-i; } /* создается тип данных для одного числа типа int с расширением на полню строку */ disp[0] = 0; disp[1] = 150*sizeof(int); type[0] = MPI_INT; type[1] = MPI_UB; blocklen[0] = 1; blocklen[1] = 1; MPI_Type_struct(2, blocklen, disp, type, &stype); MPI_Type_commit(&stype); sptr = &sendarray[0][myrank]; MPI_Gatherv(sptr, 100-myrank, stype, rbuf, rcounts, displs, MPI_INT, root, comm);

Пример 4.9 Такой же, как пример 4.7 на передающей стороне, но на приемной стороне устанавливается страйд между принимаемыми блоками, изменяющийся от блока к блоку (рис.4.6).

MPI_Comm comm; int gsize,sendarray[100][150],*sptr; int root, *rbuf, *stride, myrank, bufsize; MPI_Datatype stype; int *displs,i,*rcounts,offset; ... MPI_Comm_size(comm, &gsize); MPI_Comm_rank(comm, &myrank); stride = (int *)malloc(gsize*sizeof(int)); ... /* сначала устанавливаются вектора displs и rcounts */ displs = (int *)malloc(gsize*sizeof(int)); rcounts = (int *)malloc(gsize*sizeof(int)); offset = 0; for (i=0; i<gsize; ++i) { displs[i] = offset; offset += stride[i]; rcounts[i] = 100-i; } /* теперь легко получается требуемый размер буфера для rbuf */ bufsize = displs[gsize-1]+rcounts[gsize-1]; rbuf = (int *)malloc(bufsize*sizeof(int)); /* создается тип данных для посылаемого столбца */ MPI_Type_vector(100-myrank, 1, 150, MPI_INT, &stype); MPI_Type_commit(&stype); sptr = &sendarray[0][myrank]; MPI_Gatherv(sptr, 1, stype, rbuf, rcounts, displs, MPI_INT, root, comm);

\includegraphics[width=5.77in,height=2.82in]{Ch4figure7.eps}

\includegraphics[width=5.44in,height=2.78in]{Ch4figure6.eps}

Пример 4.10 В этом примере процесс i посылает num чисел типа int из i-го столбца массива 100x150 чисел типа int на языке Си. Усложнение состоит в том, что различные значения num неизвестны корневому процессу, так что требуется сначала выполнить отдельную операцию gather, чтобы найти их. Данные на приемной стороне размещаются непрерывно.

MPI_Comm comm; int gsize,sendarray[100][150],*sptr; int root, *rbuf, stride, myrank, disp[2], blocklen[2]; MPI_Datatype stype,types[2]; int *displs,i,*rcounts,num; ... MPI_Comm_size(comm, &gsize); MPI_Comm_rank(comm, &myrank); /* снчала собираются nums для root */ rcounts = (int *)malloc(gsize*sizeof(int)); MPI_Gather(&num, 1, MPI_INT, rcounts, 1, MPI_INT, root, comm); /* root теперь имеет правильные rcounts, это позволяет установить displs[] так, чтобы данные на приемной стороне размещались непрерывно (или на основе конкатенации) */ displs = (int *)malloc(gsize*sizeof(int)); displs[0] = 0; for (i=1; i<gsize; ++i) { displs[i] = displs[i-1]+rcounts[i-1]; } /* создается буфер получения */ rbuf = (int *)malloc(gsize*(displs[gsize-1]+rcounts[gsize-1]) *sizeof(int)); /* создается тип данных для единственной int с расширением на полную строку */ disp[0] = 0; disp[1] = 150*sizeof(int); type[0] = MPI_INT; type[1] = MPI_UB; blocklen[0] = 1; blocklen[1] = 1; MPI_Type_struct(2, blocklen, disp, type, &stype); MPI_Type_commit(&stype); sptr = &sendarray[0][myrank]; MPI_Gatherv(sptr, num, stype, rbuf, rcounts, displs, MPI_INT, root, comm);



Alex Otwagin 2002-12-10