Transcript comm

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
Пример 1. «Привет»
#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();
}
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
MPI 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
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 — признак того, что
подходит сообщение с любым
идентификатором.
Пример 2.1. «Все одному»
#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();
}
Тупиковые ситуации (deadlock):
процесс 0: процесс 1:
RECV(1) RECV(0)
SEND(1) SEND(0)
процесс 0: процесс 1:
SEND(1) SEND(0)
RECV(1) RECV(0)
Разрешение тупиковых ситуаций:
1.
процесс 0:
SEND(1)
RECV(1)
процесс
1:
RECV(0)
SEND(0)операций
2. Использование неблокирующих
(MPI_ISEND, MPI_IRECV)
3. Использование функции совмещенного
обмена (MPI_SENDRECV)
Пример 2.2: Парный обмен
#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();
}
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 длина списка (целое)
INOUT
array_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 - если не имеется активных
дескрипторов в списке
Пример 3: Обмен по кольцу без блокировки
#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();
}
ПРОБА И ОТМЕНА
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)
Пример 4. Вычисление числа 
где
#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;
}
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();
}