Слайд 1MPI. Терминология и обозначения
MPI - message passing interface
Процессы объединяются
в группы. С каждой группой ассоциирован свой коммуникатор.
Два основных
атрибута процесса: коммуникатор (группа) и номер процесса в коммуникаторе (группе).
Номер процесса - целое неотрицательное число, являющееся уникальным атрибутом каждого процесса от 0 до N-1 (N – число процессоров в группе.
Все процессы содержатся в группе с предопределенным идентификатором MPI_COMM_WORLD.
Слайд 2Сообщение - набор данных некоторого типа.
Атрибуты сообщения: номер процесса-отправителя, номер процесса-получателя,
идентификатор сообщения и др.
Идентификатор сообщения (msgtag) - атрибут сообщения, являющийся
целым неотрицательным числом, лежащим в диапазоне от 0 до 32767.
Слайд 3Общие процедуры MPI
int MPI_Init( int* argc, char*** argv)
- инициализация параллельной части приложения.
int MPI_Finalize( void )
-
завершение параллельной части приложения.
Слайд 4int MPI_Comm_size( MPI_Comm comm, int* size)
- определение общего числа
параллельных процессов в группе comm.
IN comm - идентификатор группы
OUT size - размер группы
Слайд 5int MPI_Comm_rank( MPI_comm comm, int* rank)
- определение номера процесса
в группе comm. Значение, возвращаемое по адресу &rank.
IN comm
- идентификатор группы
OUT rank - номер вызывающего процесса в группе comm
Слайд 6#include "mpi.h"
main(int argc, char **argv)
{
int me, size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &me);
MPI_Comm_size(MPI_COMM_WORLD,
&size);
printf("Hi, I’m process %d of %d \n", me, size);
MPI_Finalize();
}
Пример 1.
«Привет»
Слайд 7double MPI_Wtime(void)
- функция возвращает астрономическое время в секундах (вещественное
число), прошедшее с некоторого момента в прошлом.
Слайд 8int MPI_Get_processor_name(char *name, int *len)
определяет имя процессора, на котором выполняется
данная команда.
Также определяет длину имени процессора. Буффер name должен
быть как минимум размером в MPI_MAX_PROCESSOR_NAME символов.
Слайд 9int MPI_Send (void* buf, int count, MPI_Datatype datatype, int dest,
int tag, MPI_Comm comm)
- функция блокирующей посылки
IN buf начальный адрес
буфера посылки сообщения (альтернатива)
IN count число элементов в буфере посылки (неотрицательное целое)
IN datatype тип данных каждого элемента в буфере передачи (дескриптор)
IN dest номер процесса-получателя (целое)
IN tag тэг сообщения (целое)
IN comm коммуникатор (группа)
Слайд 10MPI datatype C datatype
MPI_CHAR signed char
MPI_INT signed int
MPI_LONG signed long
int
MPI_UNSIGNED_CHAR unsigned char
MPI_UNSIGNED_SHORT unsigned short int
MPI_UNSIGNED unsigned int
MPI_UNSIGNED_LONG unsigned long
int
MPI_FLOAT float
MPI_DOUBLE double
MPI_LONG_DOUBLE long double
Типы данных в MPI
Слайд 11int MPI_Get_count (MPI_Status *status,MPI_Datatype datatype, int *count)
- операция возвращает
число полученных элементов
IN status статус операции приема (статус )
IN datatype
тип данных каждого элемента приемного буфера (дескриптор)
OUT count количество полученных единиц (целое)
Слайд 12Модификации функции MPI_SEND:
MPI_BSEND(buf, count, datatype, dest, tag, comm) — передача сообщения
с буферизацией.
MPI_SSEND (buf, count, datatype, dest, tag, comm) — передача сообщения
с синхронизацией.
MPI_RSEND (buf, count, datatype, dest, tag, comm) — передача сообщения по готовности.
Слайд 13int MPI_Buffer_attach (void* buffer, int size)
- описать буфера, используемого для
буферизации сообщений, посылаемых в режиме буферизации.
IN buffer начальный адрес буфера
(альтернатива)
IN size размер буфера в байтах (целое)
int MPI_Buffer_detach(void* buffer_addr, int * size)
- отключенние буфера
OUT buffer_addr начальный адрес буфера (альтернатива)
OUT size размер буфера в байтах (целое)
РАСПРЕДЕЛЕНИЕ И ИСПОЛЬЗОВАНИЕ БУФЕРОВ
Слайд 14int MPI_Recv (void* buf, int count, MPI_Datatype datatype, int source,
int tag, MPI_Comm comm, MPI_Status *status)
- функция блокирующего приема
OUT
buf начальный адрес буфера процесса-получателя (альтернатива)
IN count число элементов в принимаемом сообщении (целое)
IN datatype тип данных каждого элемента сообщения (дескриптор)
IN source номер процесса-отправителя (целое)
IN tag тэг сообщения (целое)
IN comm коммуникатор (дескриптор)
OUT status параметры принятого сообщения (статус)
Слайд 15Параметры принятого сообщения всегда можно определить по соответствующим элементам структуры
STATUS:
STATUS.MPI_SOURCE— номер процесса-отправителя.
STATUS.MPI_TAG — идентификатор сообщения.
STATUS.MPI_ERROR — код ошибки.
Слайд 16Вместо аргументов SOURCE и TAG можно использовать константы:
MPI_ANY_SOURCE — признак того, что
подходит сообщение от любого процесса
MPI_ANY_TAG — признак того, что подходит сообщение с
любым идентификатором.
Слайд 17#include "mpi.h"
main (int argc, char **argv)
{
char message[20];
int myrank, size, i;
MPI_Status status;
MPI_Init (&argc, &argv);
MPI_Comm_rank (MPI_COMM_WORLD, &myrank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (myrank==0) /* code for process zero */
{
strcpy (message, "Hello, there");
for (i=1;i
} else /* code for process one */ {
MPI_Recv (message, 20, MPI_CHAR, 0, 99, MPI_COMM_WORLD, &status);
printf ("proc %d received :%s:\n",myrank, message);
}
MPI_Finalize();
}
Пример 2. «Один всем»
Слайд 18Тупиковые ситуации (deadlock):
процесс 0:
RECV(1)
SEND(1)
процесс 1:
RECV(0)
SEND(0)
процесс 0:
SEND(1)
RECV(1)
процесс 1:
SEND(0)
RECV(0)
Слайд 19#include "mpi.h"
main(int argc, char **argv)
{
int me, size, n;
int SOME_TAG=0;
MPI_Status status;
MPI_Init (&argc, &argv);
MPI_Comm_rank (MPI_COMM_WORLD, &me);
MPI_Comm_size (MPI_COMM_WORLD, &size);
if ((me % 2)==0) {
/* send unless highest-numbered process */
if ((me+1) < size) {
MPI_Send (&me, 1, MPI_INT,me+1,SOME_TAG,MPI_COMM_WORLD);
printf("me %d send %d\n",me,me);
}
}
else {
MPI_Recv(&n,1,MPI_INT,me-1,SOME_TAG,MPI_COMM_WORLD,&status);
printf("me %d received %d\n",me,n);
}
MPI_Finalize();
}
Слайд 20Разрешение тупиковых ситуаций:
1.
процесс 0:
SEND(1)
RECV(1)
процесс 1:
RECV(0)
SEND(0)
2. Использование неблокирующих операций (MPI_ISEND, MPI_IRECV)
3.
Использование функции совмещенного обмена (MPI_SENDRECV)
Слайд 21int MPI_Isend (void* buf, int count, MPI_Datatype datatype, int dest,
int tag, MPI_Comm comm, MPI_Request *request)
- функция неблокирующей посылки
IN buf
начальный адрес буфера посылки (альтернатива)
IN count число элементов в буфере посылки (целое)
IN datatype тип каждого элемента в буфере посылки (дескриптор)
IN dest номер процесса-получателя (целое)
IN tag тэг сообщения (целое)
IN comm коммуникатор (дескриптор)
OUT request запрос обмена (дескриптор)
Слайд 22int MPI_Irecv (void* buf, int count, MPI_Datatype datatype, int source,
int tag, MPI_Comm comm, MPI_Request *request)
- функция неблокирующего приема
IN buf
начальный адрес буфера посылки (альтернатива)
IN count число элементов в буфере посылки (целое)
IN datatype тип каждого элемента в буфере посылки (дескриптор)
IN source номер процесса-получателя (целое)
IN tag тэг сообщения (целое)
IN comm коммуникатор (дескриптор)
OUT request запрос обмена (дескриптор)
Слайд 23Модификации функции MPI_ISEND:
MPI_IBSEND(buf, count, datatype, dest, tag, comm, request) — передача
сообщения с буферизацией.
MPI_ISSEND (buf, count, datatype, dest, tag, comm, request)
— передача сообщения с синхронизацией.
MPI_IRSEND (buf, count, datatype, dest, tag, comm, request) — передача сообщения по готовности.
Слайд 24int MPI_Wait (MPI_Request *request, MPI_Status *status)
- заканчивается, когда завершена
операция, указанная в запросе.
INOUT request запрос (дескриптор)
OUT status объект состояния
(статус)
int MPI_Test (MPI_Request *request, int *flag, MPI_Status *status) - возвращает flag = true, если операция,
указанная в запросе, завершена.
INOUT request коммуникационный запрос (дескриптор)
OUT flag true, если операция завершена (логический тип)
OUT status статусный объект (статус)
Завершение обмена
Слайд 25Множественные завершения
int MPI_Waitall (int count, MPI_Request *array_of_requests, MPI_Status *array_of_statuses) -
блокирует работу, пока все операции обмена, связанные с активными дескрипторами
в списке, не завершатся, и возвращает статус всех операций.
IN count длина списков (целое)
INOUT array_of_requests массив запросов (массив дескрипторов)
OUT array_of_statuses массив статусных объектов (массив статусов)
int MPI_Testall(int count, MPI_Request *array_of_requests, int *flag,
MPI_Status *array_of_statuses) - возвращает flag=true, если обмены, связанные с активными дескрипторами в массиве, завершены.
IN count длина списка (целое)
INOUT array_of_requests массив запросов (массив дескрипторов)
OUT flag (логический тип)
OUT array_of_statuses массив статусных объектов(массив статусов)
Слайд 26Int MPI_Waitany (int count, MPI_Request *array_of_requests, int *index,
MPI_Status *status) -
блокирует работу до тех пор, пока не завершится одна
из операций
из массива активных запросов. Если более чем одна операция задействована и может закончиться, выполняется произвольный
выбор.
IN count длина списка (целое)
INOUT array_of_requests массив запросов (массив дескрипторов)
OUT index индекс дескриптора для завершенной операции
(целое)
OUT status статусный объект (статус)
int MPI_Testany (int count, MPI_Request *array_of_requests, int *index, int *flag,
MPI_Status *status) - тестирует завершение либо одной либо никакой из операций, связанных с активными дескрипторами.
IN count длина списка (целое)
INOUT
array_of_requests массив запросов (массив дескрипторов)
OUT index индекс дескриптора для завершенной операции (целое)
OUT flag true, если одна из операций завершена (логический тип)
OUT status статусный объект (статус)
Слайд 27int MPI_Waitsome (int incount, MPI_Request *array_of_requests, int *outcount,
int *array_of_indices, MPI_Status
*array_of_statuses) - ожидает, пока, по крайней мере, одна операция, связанная
с активным дескриптором в списке, не завершится.
IN incount длина массива запросов (целое)
INOUT array_of_requests массив запросов (массив дескрипторов)
OUT outcount число завершенных запросов (целое)
OUT array_of_indices массив индексов операций, которые завершены
(массив целых)
OUT array_of_statuses массив статусных операций для завершенных
операций (массив статусов)
int MPI_Testsome (int incount, MPI_Request *array_of_requests, int *outcount,
int *array_of_indices, MPI_Status *array_of_statuses) - ведет себя подобно
MPI_WAITSOME за исключением того, что заканчивается немедленно.
IN incount длина массива запросов (целое)
IN OUT array_of_requests массив запросов (массив дескрипторов)
OUT outcount число завершенных запросов (целое)
OUT array_of_indices массив индексов завершенных операций (массив
целых)
OUT array_of_statuses массив статусных объектов завершенных операций
(массив статусов)
Слайд 28MPI_SUCCESS - удачное завершение обменов
MPI_ERR_IN_STATUS - неудачное завершение обменов, устанавливается
специфический код ошибки в поля ошибки каждого статуса.
MPI_ERR_PENDING –
обмен не завершен, но и не в состоянии отказа
MPI_REQUEST_NULL – значение дескриптора (по завершении обмена он удаляется), если запрос был размещен вызовом неблокирующего обмена
outcount = MPI_UNDEFINED - если не имеется активных дескрипторов в списке
Слайд 29#include "mpi.h"
#include
main(int argc, char **argv) {
int numtasks, rank,
next, prev, buf[2], tag1=1, tag2=2;
MPI_Request reqs[4];
MPI_Status stats[4];
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
prev = rank - 1;
next = rank + 1;
if (rank == 0) prev = numtasks – 1;
if (rank == (numtasks – 1)) next = 0;
MPI_Irecv(&buf[0], 1, MPI_INT, prev, tag1, MPI_COMM_WORLD, &reqs[0]);
MPI_Irecv(&buf[1], 1, MPI_INT, next, tag2, MPI_COMM_WORLD, &reqs[1]);
MPI_Isend(&rank, 1, MPI_INT, prev, tag2, MPI_COMM_WORLD, &reqs[2]);
MPI_Isend(&rank, 1, MPI_INT, next, tag1, MPI_COMM_WORLD, &reqs[3]);
MPI_Waitall(4, reqs, stats);
printf("me %d recv %d %d\n",rank,buf[0],buf[1]);
MPI_Finalize();
}
Пример 3: Обмен по кольцу без блокировки
Слайд 30ПРОБА И ОТМЕНА
int MPI_Iprobe(int source, int tag, MPI_Comm comm, int
*flag, MPI_Status *status) - возвращает flag = true, если имеется
сообщение, которое может быть получено и которое соответствует образцу, описанному аргументами source, tag, и comm.
IN source номер процесса-отправителя или MPI_ANY_SOURCE (целое)
IN tag значение тэга или MPI_ANY_TAG (целое)
IN comm коммуникатор (дескриптор)
OUT flag (логическое значение)
OUT status статус (статус)
int MPI_Probe(int source, int tag, MPI_Comm comm, MPI_Status *status)
– блокирующий аналог MPI_Iprobe
IN source номер источника или MPI_ANY_SOURCE (целое)
IN tag значение тэга или MPI_ANY_TAG (целое)
IN comm коммуникатор (дескриптор)
OUT status статус (статус)
Слайд 31int MPI_Cancel(MPI_Request *request) - маркирует для отмены ждущие неблокирующие операции
обмена (передача или прием).
IN request коммуникационный запрос (дескриптор)
После маркировки
необходимо завершить эту операцию обмена, используя вызов MPI_WAIT или MPI_TEST (или любые производные операции).
int MPI_Test_cancelled(MPI_Status *status, int *flag)
- возвращает flag = true, если обмен, связанный со статусным объектом, был отменен успешно.
IN status статус (Status)
OUT flag (логический тип )
Слайд 32int MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int
sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype, int source,MPI_Datatype recvtag,
MPI_Comm comm, MPI_Status *status)
– функция совмещенного приема передачи (с блокировкой)
IN sendbuf начальный адрес буфера отправителя (альтернатива)
IN sendcount число элементов в буфере отправителя (целое)
IN sendtype тип элементов в буфере отправителя (дескриптор)
IN dest номер процесса-получателя (целое)
IN sendtag тэг процесса-отправителя (целое)
OUT recvbuf начальный адрес приемного буфера (альтернатива)
IN recvcount число элементов в приемном буфере (целое)
IN recvtype тип элементов в приемном буфере (дескриптор)
IN source номер процесса-отправителя (целое)
IN recvtag тэг процесса-получателя (целое)
IN comm коммуникатор (дескриптор)
OUT status статус (статус)
Слайд 33int MPI_Sendrecv_replace(void* buf,int count, MPI_Datatype datatype, int dest, int sendtag,
int source, int recvtag, MPI_Comm comm, MPI_Status *status)
- функция приема
передачи с совмещенным буфером (с блокировкой)
INOUT buf начальный адрес буфера отправителя и получателя
(альтернатива)
IN count число элементов в буфере отправителя и получателя (целое)
IN datatype тип элементов в буфере отправителя и получателя (дескриптор)
IN dest номер процесса-получателя (целое)
IN sendtag тэг процесса-отправителя (целое)
IN source номер процесса-отправителя (целое)
IN recvtag тэг процесса-получателя (целое)
IN comm коммуникатор (дескриптор)
OUT status статус (статус)
Слайд 34Объединение запросов на взаимодействие
int MPI_Send_init( void *buf, int
count, MPI_Datatype datatype, int dest, int msgtag, MPI_Comm comm, MPI_Request
*request) - формирование запроса на выполнение пересылки данных
IN buf - адрес начала буфера посылки сообщения
IN count - число передаваемых элементов в сообщении
IN datatype - тип передаваемых элементов
IN dest - номер процесса-получателя
IN msgtag - идентификатор сообщения
IN comm - идентификатор группы
OUT request - идентификатор асинхронной передачи
int MPI_Recv_init( void *buf, int count, MPI_Datatype datatype, int source, int msgtag, MPI_Comm comm, MPI_Request *request) - формирование запроса на выполнение приема данных
Слайд 35MPI_Startall( int count, MPI_Request *requests)
запуск всех отложенных взаимодействий, ассоциированных
с элементами массива запросов requests.
IN count - число запросов
на взаимодействие
OUT requests - массив идентификаторов приема/передачи
MPI_Start(MPI_Request *requests)
Слайд 36#include "mpi.h"
#include
main ( int argc, char **argv ) {
int n=0, myid, numprocs, i;
double mypi, pi, h, sum, x,
t1, t2, PI25DT = 3.141592653589793238462643;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
if (myid == 0) t1 = MPI_Wtime();
if (argc>1) n=atoi(argv[1]);
else {
printf("number of points is needed\n");
return;
}
Вычисление числа
где
Слайд 37 h = 1.0/ (double) n;
sum = 0.0;
for
(i = myid +1; i
x = h * ( (double)i - 0.5);
sum += (4.0 / (1.0 + x*x));
}
mypi = h * sum;
// Cуммирования mypi со всех процессоров в переменную pi
MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (myid == 0) {
t2 = MPI_Wtime();
printf ("pi is approximately %.16f. Error is %.16f\n",pi, fabs(pi - PI25DT));
printf ("'time is %f seconds \n", t2-t1);
}
MPI_Finalize();
}