Коллективные взаимодействия процессов
MPI предоставляет ряд функций для коллективного взаимодейстия процессов. Эти функции называют коллективными, поскольку они должны вызываться одновременно на всех процессах, принадлежащих некоторому коммуникатору.
int MPI_Bcast ( buffer, count, datatype, root, comm ) void* buffer - начальный адрес буфера для передачи собщений int count - число передаваемых элементов данных MPI_Datatype datatype - тип передаваемых данных int root - ранг процесса, посылающего данные MPI_Comm comm - коммуникатор
int MPI_Reduce ( sendbuf, recvbuf, count, datatype, op, root, comm ) void *sendbuf; буфер операндов void *recvbuf; буфер приема int count; число данных MPI_Datatype datatype; тип данных MPI_Op op; операция int root; ранг процесса, содержащего результат MPI_Comm comm; коммуникатор op
MPI_MAX максимум MPI_MIN минимум MPI_SUM сумма MPI_PROD произведение MPI_LAND логическое "и" MPI_BAND побитовое "и" MPI_LOR логическое "или" MPI_BOR побитовое "или" MPI_LXOR логическое исключающее "или" MPI_BXOR побитовое исключающее "или"
Вычисление числа Пи
Вычисление числа Pi #include "mpi.h" #include int main(argc,argv) int argc; char *argv[]; { int done = 0, n, myid, numprocs, i, rc; double PI25DT = ; double mypi, pi, h, sum, x, a; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Comm_rank(MPI_COMM_WORLD,&myid);
while (!done) { if (myid == 0) { printf("Enter the number of intervals: (0 quits) "); scanf("%d",&n); } MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); if (n == 0) break; h = 1.0 / (double) n; sum = 0.0; for (i = myid + 1; i
MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); if (myid == 0) printf("pi is approximately %.16f, Error is %.16f\n", pi, fabs(pi - PI25DT)); } MPI_Finalize(); }
Функция синхронизации процессов: int MPI_Barrier ( comm ) ; MPI_Comm comm;
int MPI_Scatter ( sendbuf, sendcnt, sendtype, recvbuf, recvcnt, recvtype, root, comm ) void *sendbuf; int sendcnt; MPI_Datatype sendtype; void *recvbuf; int recvcnt; MPI_Datatype recvtype; int root; MPI_Comm comm;
int MPI_Gather ( sendbuf, sendcnt, sendtype, recvbuf, recvcount, recvtype, root, comm ) void *sendbuf; int sendcnt; MPI_Datatype sendtype; void *recvbuf; int recvcount; MPI_Datatype recvtype; int root; MPI_Comm comm;
#include #define N 5 int main( int argc, char **argv ) { int* dta; int ldta; int i; int size; int rank; MPI_Comm comm; MPI_Init(&argc, &argv); comm = MPI_COMM_WORLD; MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank); if(rank == 0) { dta = (int*) calloc(size, sizeof(int)); }
for(i = 0; i < N; i ++) { int j; MPI_Scatter(dta, 1, MPI_INT, &ldta, 1, MPI_INT, 0, comm); ldta += rank; MPI_Gather(&ldta, 1, MPI_INT, dta, 1, MPI_INT, 0, comm); if(rank == 0) { for(j = 0; j < size; j ++) printf("[%d]", dta[j]); printf("\n"); fflush(stdout); } MPI_Finalize(); }
int MPI_Allreduce ( sendbuf, recvbuf, count, datatype, op, comm ) void *sendbuf; void *recvbuf; int count; MPI_Datatype datatype; MPI_Op op; MPI_Comm comm; int MPI_Allgather ( sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm ) void *sendbuf; int sendcount; MPI_Datatype sendtype; void *recvbuf; int recvcount; MPI_Datatype recvtype; MPI_Comm comm;
int MPI_Alltoall( sendbuf, sendcount, sendtype, recvbuf, recvcnt, recvtype, comm ) void *sendbuf; int sendcount; MPI_Datatype sendtype; void *recvbuf; int recvcnt; MPI_Datatype recvtype; MPI_Comm comm;
#include #define N 5 int main( int argc, char **argv ) { int* sdta; int* rdta; int i; int size; int rank; MPI_Comm comm; MPI_Init(&argc, &argv); comm = MPI_COMM_WORLD; MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank); sdta = (int*) malloc(sizeof(int) * size); rdta = (int*) malloc(sizeof(int) * size); for(i = 0; i < size; i ++) sdta[i] = i;
for(i = 0; i < N; i ++) { int j; MPI_Alltoall(sdta, 1, MPI_INT, rdta, 1, MPI_INT, comm); for(j = 0; j < size; j ++) sdta[j] = rdta[j]; if(rank == 0) { printf("["); for(j = 0; j < size; j ++) printf(" %d", sdta[j]); printf("]\n"); fflush(stdout); } MPI_Finalize(); }
Группы и коммуникаторы
Интер- и интра- коммуникаторы Интра- коммуникаторы Интер- коммуникатор Интра-коммуникаторы объединяют процессы из одной группы. Интер-коммуникатор позволяет передавать данные между процессами из разных интра-коммуникаторов. Интер-коммуникаторы не могут использоваться в коллективных взаимодействиях
Группы и коммуникаторы Совокупности MPI-процессов образуют группы. Понятие ранга процесса имеет смысл только по отношению к определенной группе или коммуникатору. Каждому интра-коммуникатору соответствует группа процессов. По группе процессов можно построить коммуникатор.
Получение группы процессов по коммуникатору: int MPI_Comm_group ( comm, group ) MPI_Comm comm; MPI_Group *group; Создание коммуникатора по группе процессов: int MPI_Comm_create ( comm, group, comm_out ) MPI_Comm comm; старый коммуникатор MPI_Group group; группа процессов MPI_Comm *comm_out; новый коммуникатор
int MPI_Group_excl ( group, n, ranks, newgroup ) MPI_Group group, *newgroup; int n, *ranks; int MPI_Group_incl ( group, n, ranks, group_out ) MPI_Group group, *group_out; int n, *ranks;
int MPI_Group_intersection ( group1, group2, group_out ) int MPI_Group_union ( group1, group2, group_out ) int MPI_Group_difference ( group1, group2, group_out ) MPI_Group group1, group2, *group_out;
Создание и удаление интра- коммуникаторов Получение дубликата коммуникатора: int MPI_Comm_dup(MPI_Comm comm, MPI_Comm* newcomm) Разбиение коммуникатора на несколько: int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm* newcomm) comm – «старый коммуникатор» color – селектор коммуникатора key – задает порядок на создаваемых коммуникаторах newcomm – создаваемый коммуникатор Удаление коммуникатора: int MPI_Comm_free(MPI_Comm* comm)
Вычисление числа Pi методом Монте-Карло Из книги Gropp, Lusk, Skjellum
Схема вычислений server worker processes коммуникатор workers коммуникатор world
/* compute pi using Monte Carlo method */ #include #include "mpi.h" #define CHUNKSIZE 1000 #define INT_MAX /* message tags */ #define REQUEST 1 #define REPLY 2 int main( int argc, char *argv[] ) { int iter; int in, out, i, iters, max, ix, iy, ranks[1], done, temp; double x, y, Pi, error, epsilon; int numprocs, myid, server, totalin, totalout, workerid; int rands[CHUNKSIZE], request; MPI_Comm world, workers; MPI_Group world_group, worker_group; MPI_Status status; MPI_Init(&argc,&argv); world = MPI_COMM_WORLD; MPI_Comm_size(world,&numprocs); MPI_Comm_rank(world,&myid);
if (myid == server) {/* I am the rand server */ do { MPI_Recv(&request, 1, MPI_INT, MPI_ANY_SOURCE, REQUEST, world, &status); if (request) { for (i = 0; i < CHUNKSIZE; i++) rands[i] = random(); MPI_Send(rands, CHUNKSIZE, MPI_INT, status.MPI_SOURCE, REPLY, world); } } while( request>0 ); }
else {/* I am a worker process */ request = 1; done = in = out = 0; max = INT_MAX; /* max int, for normalization */ MPI_Send( &request, 1, MPI_INT, server, REQUEST, world ); MPI_Comm_rank( workers, &workerid ); iter = 0; while (!done) { iter++; request = 1; MPI_Recv( rands, CHUNKSIZE, MPI_INT, server, REPLY, world, &status ); for (i=0; i
MPI_Allreduce(&in, &totalin, 1, MPI_INT, MPI_SUM, workers); MPI_Allreduce(&out, &totalout, 1, MPI_INT, MPI_SUM, workers); Pi = (4.0*totalin)/(totalin + totalout); error = fabs( Pi ); done = (error ); request = (done) ? 0 : 1; if (myid == 0) { printf( "\rpi = %23.20f", Pi ); MPI_Send( &request, 1, MPI_INT, server, REQUEST, world ); } else { if (request) MPI_Send(&request, 1, MPI_INT, server, REQUEST, world); }
if (myid == 0) { printf( "\npoints: %d\nin: %d, out: %d, to exit\n", totalin+totalout, totalin, totalout ); getchar(); } MPI_Comm_free(&workers); MPI_Finalize(); }
Создание интер- коммуникаторов int MPI_Intercomm_create(MPI_Comm local_comm, int local_leader, MPI_Comm peer_comm, int remote_leader, int tag, MPI_Comm* new_comm) local_comm – коммуникатор, которому принадлежит вызывающий процесс local_leader – ранг некоторого процесса в нем peer_comm – коммуникатор, которому принадлежат процессы local_leader и remote_leader (часто COMM_WORLD) tag – используется для взаимодействия между local_leader и remote_leader (целесообразно проверять уникальность) new_comm – построенный интер-коммуникатор
#include main(int argc, char* argv[]) { int color; int rank; int m; MPI_Comm comm; MPI_Comm icomm; MPI_Status st; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); color = rank % 2; MPI_Comm_split(MPI_COMM_WORLD, color, rank, &comm); if(color == 0) MPI_Intercomm_create(comm, 0, MPI_COMM_WORLD, 1, 10, &icomm); else MPI_Intercomm_create(comm, 0, MPI_COMM_WORLD, 0, 10, &icomm);
if(color == 0) { int lrank; MPI_Comm_rank(comm, &lrank); MPI_Send(&lrank, 1, MPI_INT, lrank, 0, icomm); } else { int lrank; MPI_Comm_rank(comm, &lrank); MPI_Recv(&m, 1, MPI_INT, lrank, 0, icomm, &st); } printf("rank = %d, m = %d\n", rank, m); MPI_Finalize(); }