В данном раздели приведены задания для закрепления полученных знаний по технологии программирования параллельных компьютеров MPI.
Задание 1. MPI. Hello World.
Скомпилировать и выполнить программу. Подробно объяснить как она работает.
#include <iostream> #include "mpi.h" using namespace std; int main(int argc, char* argv[]){ MPI_Init(&argc, &argv); int rank, n, i, message; MPI_Status status; MPI_Comm_size(MPI_COMM_WORLD, &n); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (rank == 0) { cout << "Hello from process " << rank << "\n"; for (i=1; i<n; i++){ MPI_Recv(&message, 1, MPI_INT, MPI_ANY_SOURCE,MPI_ANY_TAG, MPI_COMM_WORLD, &status); cout << "Hello from process " << message << endl; } } else MPI_Send(&rank,1,MPI_INT,0,0,MPI_COMM_WORLD); MPI_Finalize(); return 0; }
Задание 2. MPI. Получение информации об атрибутах сообщения.
Подробно разобрать пример ниже, запустить и объяснить его.
#include &amp;lt;iostream&amp;gt; #include &amp;lt;mpi.h&amp;gt; using namespace std; int main(int argc, char **argv) { int rank, size, ibuf; MPI_Status status; float rbuf; MPI_Init(&amp;amp;argc, &amp;amp;argv); MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;size); MPI_Comm_rank(MPI_COMM_WORLD, &amp;amp;rank); ibuf = rank; rbuf = 1.0 * rank; if(rank==1) MPI_Send(&amp;amp;ibuf, 1, MPI_INT, 0, 5, MPI_COMM_WORLD); if(rank==2) MPI_Send(&amp;amp;rbuf, 1, MPI_FLOAT, 0, 5, MPI_COMM_WORLD); if(rank==0){ MPI_Probe(MPI_ANY_SOURCE, 5, MPI_COMM_WORLD, &amp;amp;status); if(status.MPI_SOURCE == 1){ MPI_Recv(&amp;amp;ibuf, 1, MPI_INT, 1, 5, MPI_COMM_WORLD, &amp;amp;status); MPI_Recv(&amp;amp;rbuf, 1, MPI_FLOAT, 2, 5, MPI_COMM_WORLD, &amp;amp;status); cout &amp;lt;&amp;lt; "Process 0 recv " &amp;lt;&amp;lt; ibuf &amp;lt;&amp;lt; " from process 1, " &amp;lt;&amp;lt; rbuf &amp;lt;&amp;lt; "from process 2\n"; } else if(status.MPI_SOURCE == 2){ MPI_Recv(&amp;amp;rbuf, 1, MPI_FLOAT, 2, 5, MPI_COMM_WORLD, &amp;amp;status); MPI_Recv(&amp;amp;ibuf, 1, MPI_INT, 1, 5, MPI_COMM_WORLD, &amp;amp;status); cout &amp;lt;&amp;lt; "Process 0 recv " &amp;lt;&amp;lt; rbuf &amp;lt;&amp;lt; " from process 2, " &amp;lt;&amp;lt; ibuf &amp;lt;&amp;lt; "from process 1\n"; } } MPI_Finalize(); }
Задание 3. MPI. Передача и прием сообщений без блокировки. Обмен по кольцевой топологии при помощи неблокирующих операций.
Допишите программу. Скомпилируйте и запустите ее. Внимательно изучите код и объясните, как он работает.
#include <iostream> #include "mpi.h" int main(int argc, char **argv) { int rank, size, prev, next; int buf[2]; MPI_Init(&argc,&argv); MPI_Request reqs[4]; MPI_Status stats[4]; MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); prev = rank - 1; next = rank + 1; if(rank==0) prev = size - 1; if(rank==size - 1) next = 0; MPI_Irecv(&buf[0], 1, MPI_INT, prev, 5, MPI_COMM_WORLD, &reqs[0]); MPI_Irecv(&buf[1], 1, MPI_INT, next, 6, MPI_COMM_WORLD, &reqs[1]); MPI_Isend(&rank, 1, MPI_INT, prev, 6, MPI_COMM_WORLD, &reqs[2]); MPI_Isend(&rank, 1, MPI_INT, next, 5, MPI_COMM_WORLD, &reqs[3]); MPI_Waitall(4, reqs, stats); Здесь необходимо вывести на экран номер текущего процесса, и что он получает от предыдущего и следующего процессов MPI_Finalize(); }
Задание 4. MPI. Отложенные запросы на взаимодействие. Схема итерационного метода с обменом по кольцевой топологии при помощи отложенных запросов.
Найти и исправить ошибки, дописать цикл for. В каких случаях необходимо использовать цикл?
MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); prev = rank - 1; next = rank + 1; if(rank == 0) prev = size - 1; if(rank == size - 1) next = 0; MPI_Recv_init(rbuf[0], 1, MPI_FLOAT, prev, 5, MPI_COMM_WORLD, reqs[0]); MPI_Recv_init(rbuf[1], 1, MPI_FLOAT, next, 6, MPI_COMM_WORLD, reqs[1]); MPI_Send_init(sbuf[0], 1, MPI_FLOAT, prev, 6, MPI_COMM_WORLD, reqs[2]); MPI_Send_init(sbuf[1], 1, MPI_FLOAT, next, 5, MPI_COMM_WORLD, reqs[3]); for(i=...){ sbuf[0] =...; sbuf[1] =...; MPI_Startall(4, reqs); //здесь мог быть ваш код MPI_Waitall(4, reqs, stats); //здесь мог быть ваш код } MPI_Request_free(reqs[0]); MPI_Request_free(reqs[1]); MPI_Request_free(reqs[2]); MPI_Request_free(reqs[3]);
Задание 5. MPI. Коллективные взаимодействия процессов. Барьер. Моделирование барьерной синхронизации.
Программа написана на языке Си. Необходимо переписать на C++. А именно: вывод на экран printf заменить на cout, соблюдая синтаксис, добавить необходимые библиотеки.
Разобраться с новыми функциями, объяснить выполнение программы.
#include <stdio.h> #include "mpi.h" #define MAXPROC 128 #define NTIMES 10000 int main(int argc, char **argv) { int rank, size, i, it; MPI_Init(&argc, &argv); int ibuf[MAXPROC]; double time_start, time_finish; MPI_Request req[2*MAXPROC]; MPI_Status statuses[MAXPROC]; MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if(rank==0){ for(i = 1; i<size; i++){ MPI_Recv_init(&ibuf[i], 0, MPI_INT, i, 5, MPI_COMM_WORLD, &req[i]); MPI_Send_init(&rank, 0, MPI_INT, i, 6, MPI_COMM_WORLD, &req[size+i]); } time_start = MPI_Wtime(); for(it = 0; it<NTIMES; it++){ MPI_Startall(size-1, &req[1]); MPI_Waitall(size-1, &req[1], statuses); MPI_Startall(size-1, &req[size+1]); MPI_Waitall(size-1, &req[size+1], statuses); } } else{ MPI_Recv_init(&ibuf[0], 0, MPI_INT, 0, 6, MPI_COMM_WORLD, &req[0]); MPI_Send_init(&rank, 0, MPI_INT, 0, 5, MPI_COMM_WORLD, &req[1]); time_start = MPI_Wtime(); for(it = 0; it<NTIMES; it++){ MPI_Start(&req[1]); MPI_Wait(&req[1], statuses); MPI_Start(&req[0]); MPI_Wait(&req[0], statuses); } } time_finish = MPI_Wtime()-time_start; printf("rank = %d model time = %lf\n", rank, time_finish/NTIMES); time_start = MPI_Wtime(); for(it = 0; it<NTIMES; it++) MPI_Barrier(MPI_COMM_WORLD); time_finish = MPI_Wtime()-time_start; printf("rank = %d barrier time = %lf\n", rank, time_finish/NTIMES); MPI_Finalize(); }