mpi. Терминология и обозначения
DESCRIPTION
MPI. Терминология и обозначения. MPI - message passing interface Процессы объединяются в группы . С каждой группой ассоциирован свой коммуникатор . Два основных атрибута процесса : коммуникатор (группа) и номер процесса в коммуникаторе (группе) . - PowerPoint PPT PresentationTRANSCRIPT
MPI. Терминология и обозначения
MPI - message passing interface
Процессы объединяются в группы. С каждой группой ассоциирован свой коммуникатор.
Два основных атрибута процесса: коммуникатор (группа) и номер процесса в коммуникаторе (группе).
Номер процессаНомер процесса - целое неотрицательное число, являющееся уникальным атрибутом каждого процесса от 0 до N-1 (N – число процессоров в группе. Все процессы содержатся в группе с предопределенным идентификатором MPI_COMM_WORLD.
Сообщение - набор данных некоторого типа.
Атрибуты сообщения: номер процесса-отправителя, номер процесса-получателя, идентификатор сообщения и др.
Идентификатор сообщения (msgtag) - атрибут сообщения, являющийся целым неотрицательным числом, лежащим в диапазоне от 0 до 32767.
Общие процедуры MPI
int MPI_Init( int* argc, char*** argv)
- инициализация параллельной части приложения.
int MPI_Finalize( void )
- завершение параллельной части приложения.
int MPI_Comm_size( MPI_Comm comm, int* size)
- определение общего числа параллельных процессов в группе comm.
IN comm - идентификатор группы
OUT size - размер группы
int MPI_Comm_rank( MPI_comm comm, int* rank)
- определение номера процесса в группе comm. Значение, возвращаемое по адресу &rank.
IN comm - идентификатор группы
OUT rank - номер вызывающего процесса в группе comm
#include <stdlib.h> #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. «Привет»
double MPI_Wtime(void)
- функция возвращает астрономическое время в секундах (вещественное число), прошедшее с некоторого момента в прошлом.
int MPI_Get_processor_name(char *name, int *len)-определяет имя процессора, на котором выполняется данная команда.
Также определяет длину имени процессора. Буффер name должен быть как минимум размером в MPI_MAX_PROCESSOR_NAME символов.
int 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 коммуникатор (группа)
MPI datatype C datatype
MPI_CHAR signed charMPI_INT signed intMPI_LONG signed long intMPI_UNSIGNED_CHAR unsigned charMPI_UNSIGNED_SHORT unsigned short intMPI_UNSIGNED unsigned intMPI_UNSIGNED_LONG unsigned long intMPI_FLOAT floatMPI_DOUBLE doubleMPI_LONG_DOUBLE long double
Типы данных в MPI
int MPI_Get_count (MPI_Status *status,MPI_Datatype datatype, int *count) - операция возвращает число полученных элементов
IN status статус операции приема (статус )IN datatype тип данных каждого элемента приемного буфера (дескриптор)OUT count количество полученных единиц (целое)
Модификации функции 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) — передача сообщения по готовности.
int 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 размер буфера в байтах (целое)
РАСПРЕДЕЛЕНИЕ И ИСПОЛЬЗОВАНИЕ БУФЕРОВ
int 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 параметры принятого сообщения (статус)
Параметры принятого сообщения всегда можно определить по соответствующим элементам структуры STATUS:
STATUS.MPI_SOURCE— номер процесса-отправителя.STATUS.MPI_TAG — идентификатор сообщения. STATUS.MPI_ERROR — код ошибки.
Вместо аргументов SOURCE и TAG можно использовать константы:
•MPI_ANY_SOURCE — признак того, что подходит сообщение от любого процесса
•MPI_ANY_TAG — признак того, что подходит сообщение с любым идентификатором.
#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<size;i++) MPI_Send(message, strlen(message)+1, MPI_CHAR, i,
99, MPI_COMM_WORLD); } 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.1. «Все одному»
Тупиковые ситуации (deadlock):
процесс 0:
RECV(1)
SEND(1)
процесс 1:
RECV(0)
SEND(0)
процесс 0:
SEND(1)
RECV(1)
процесс 1:
SEND(0)
RECV(0)
Разрешение тупиковых ситуаций:
1. процесс 0:
SEND(1)
RECV(1)
процесс 1:
RECV(0)
SEND(0)
2. Использование неблокирующих операций (MPI_ISEND, MPI_IRECV)
3. Использование функции совмещенного обмена (MPI_SENDRECV)
#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); MPI_Recv(&n,1,MPI_INT,me+1,SOME_TAG,MPI_COMM_WORLD,&status); printf("me %d received %d\n",me,n); } } else { MPI_Recv(&n,1,MPI_INT,me-1,SOME_TAG,MPI_COMM_WORLD,&status); MPI_Send (&me, 1, MPI_INT,me-1,SOME_TAG,MPI_COMM_WORLD); printf("me %d received %d\n",me,n); } MPI_Finalize();}
Пример 2.2: Парный обмен
int 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 запрос обмена (дескриптор)
int 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 запрос обмена (дескриптор)
Модификации функции 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) — передача сообщения по готовности.
int 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 статусный объект (статус)
Завершение обмена
Множественные завершения
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 массив статусных объектов(массив статусов)
Int 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 длина списка (целое)INOUTarray_of_requests массив запросов (массив дескрипторов)OUT index индекс дескриптора для завершенной операции (целое)OUT flag true, если одна из операций завершена (логический тип)OUT status статусный объект (статус)
int 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 массив статусных объектов завершенных операций(массив статусов)
MPI_SUCCESS - удачное завершение обменов
MPI_ERR_IN_STATUS - неудачное завершение обменов, устанавливается специфический код ошибки в поля ошибки каждого статуса.
MPI_ERR_PENDING – обмен не завершен, но и не в состоянии отказа
MPI_REQUEST_NULL – значение дескриптора (по завершении обмена он удаляется), если запрос был размещен вызовом неблокирующего обмена
outcount = MPI_UNDEFINED - если не имеется активных дескрипторов в списке
#include "mpi.h"#include <stdio.h>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: Обмен по кольцу без блокировки
ПРОБА И ОТМЕНА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 статус (статус)
int 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 (логический тип )
int 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 статус (статус)
int 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 статус (статус)
Объединение запросов на взаимодействие
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) - формирование запроса на выполнение приема данных
MPI_Startall( int count, MPI_Request *requests) -запуск всех отложенных взаимодействий, ассоциированных с элементами массива запросов requests.
IN count - число запросов на взаимодействие OUT requests - массив идентификаторов приема/передачи
MPI_Start(MPI_Request *requests)
#include "mpi.h"#include <math.h>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; }
Пример 4. Вычисление числа
где
h = 1.0/ (double) n; sum = 0.0;
for (i = myid +1; i <= n; i+= numprocs) { 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();}