Санкт-Петербургский государственный университет
Опубликован: 11.02.2010 | Доступ: свободный | Студентов: 533 / 93 | Оценка: 4.41 / 4.44 | Длительность: 08:19:00
Специальности: Программист
Лекция 3:

Интерфейс передачи сообщений MPI

Двухточечный обмен

Участниками двухточечного обмена являются два процесса: процесс-отправитель и процесс-получатель (рис. 3.3).

Двухточечный обмен

Рис. 3.3. Двухточечный обмен

Далее приводится описание интерфейса подпрограмм, реализующих разные виды двухточечного обмена.

Стандартная блокирующая передача

int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)

MPI_SEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, IERR)

Входные параметры:

  • buf - адрес первого элемента в буфере передачи;
  • count - количество элементов в буфере передачи;
  • datatype - тип MPI каждого пересылаемого элемента;
  • dest - ранг процесса-получателя сообщения (целое число от 0 до n - 1, где n - число процессов в области взаимодействия);
  • tag - тег сообщения;
  • comm - коммуникатор;
  • ierr - код завершения.

Стандартный блокирующий прием

int MPI_Recv(void *buf,  int count, MPI_Datatype datatype,  int source, 
	int tag, MPI_Comm comm, MPI_Status *status)
MPI_RECV(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM, STATUS, IERR)

Входные параметры:

  • count - максимальное количество элементов в буфере приема. Фактическое их количество можно определить с помощью подпрограммы MPI_Get_count ;
  • datatype - тип принимаемых данных. Напомним о необходимости соблюдения соответствия типов аргументов подпрограмм приема и передачи;
  • source - ранг источника. Можно использовать специальное значение MPI_ANY_SOURCE, соответствующее произвольному значению ранга. В программировании идентификатор, отвечающий произвольному значению параметра, часто называют "джокером". Этот термин будем использовать и мы;
  • tag - тег сообщения или "джокер" MPI_ANY_TAG, соответствующий произвольному значению тега;
  • comm - коммуникатор. При указании коммуникатора "джокеры" использовать нельзя.

Выходные параметры:

  • buf - начальный адрес буфера приема. Его размер должен быть достаточным, чтобы разместить принимаемое сообщение, иначе при выполнении приема произойдет сбой - возникнет ошибка переполнения;
  • status - статус обмена.

Если сообщение меньше, чем буфер приема, изменяется содержимое лишь тех ячеек памяти буфера, которые относятся к сообщению.

Определение размера полученного сообщения (count)

int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count)

MPI_GET_COUNT(STATUS, DATATYPE, COUNT, IERR)

Аргумент datatype должен соответствовать типу данных, указанному в операции передачи сообщения.

Синхронная передача

int MPI_Ssend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)

MPI_SSEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, IERR)

Параметры этой подпрограммы совпадают с параметрами подпрограммы MPI_Send.

Буферизованный обмен

int MPI_Bsend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)

MPI_BSEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, IERR)

Параметры совпадают с параметрами подпрограммы MPI_Send.

Создание буфера

int MPI_Buffer_attach(void *buf,  size)

MPI_BUFFER_ATTACH(BUF, SIZE, IERR)

Выходной параметр:

  • buf - буфер размером size байтов.

В программах на языке Fortran роль буфера может играть массив. Этот массив должен быть описан в программе, его не следует использовать для других целей (например, в качестве первого аргумента подпрограммы MPI_Bsend ). За один раз к процессу может быть подключен только один буфер.

Отключение буфера

int MPI_Buffer_detach(void *buf, int *size)
MPI_BUFFER_DETACH(BUF, SIZE, IERR)

Выходные параметры:

  • buf - адрес;
  • size - размер отключаемого буфера.

Вызов данной подпрограммы блокирует работу процесса до тех пор, пока все сообщения, находящиеся в буфере, не будут обработаны. В языке C данный вызов не освобождает автоматически память, отведенную для буфера.

Передача по готовности

int MPI_Rsend(void *buf, int count, MPI_Datatype datatype, 
	int dest, int tag,  MPI_Comm comm)

MPI_RSEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, IERR)

Параметры совпадают с параметрами подпрограммы MPI_Send.

Блокирующая проверка доставки сообщения

int MPI_Probe(int source, int tag, MPI_Comm comm, MPI_Status *status)

MPI_PROBE(SOURCE, TAG, COMM, STATUS, IERR)

Входные параметры:

  • source - ранг источника или " джокер";
  • tag - значение тега или "джокер";
  • comm - коммуникатор.

Выходной параметр:

  • status - статус.

Неблокирующая проверка сообщения

int MPI_Iprobe(int source, int tag, MPI_Comm comm, int *flag, MPI_Status *status)

MPI_IPROBE(SOURCE, TAG, COMM, FLAG, STATUS, IERR)

Входные параметры этой подпрограммы те же, что и у подпрограммы MPI_Probe

Выходные параметры:

  • flag - флаг;
  • status - статус.

Если сообщение уже поступило и может быть принято, возвращается значение флага "истина".

Прием и передача данных с блокировкой

int MPI_Sendrecv(void *sendbuf,  int sendcount, MPI_Datatype sendtype, 
	int dest,  int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype,  
	int source,  int recvtag, MPI_Comm comm, MPI_Status *status)
MPI_SENDRECV(SENDBUF, SENDCOUNT, SENDTYPE, DEST, SENDTAG, 
	RECVBUF, RECVCOUNT, RECVTYPE, SOURCE, RECVTAG, COMM, STATUS, IERR)

Входные параметры:

  • sendbuf - начальный адрес буфера передачи;
  • sendcount - количество передаваемых элементов;
  • sendtype - тип передаваемых элементов;
  • dest - ранг адресата;
  • sendtag - тег передаваемого сообщения;
  • recvbuf - начальный адрес буфера приема;
  • recvcount - количество элементов в буфере приема;
  • recvtype - тип элементов в буфере приема;
  • source - ранг источника;
  • recvtag - тег принимаемого сообщения;
  • comm - коммуникатор.

Выходные параметры:

  • recvbuf - начальный адрес буфера приема;
  • 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)

MPI_SENDRECV_REPLACE(BUF, COUNT, DATATYPE, DEST, SENDTAG, SOURCE, RECVTAG, COMM, STATUS, IERR)

Входные параметры:

  • count - количество отправляемых данных и емкость буфера приема;
  • datatype - тип данных в буфере приема и передачи;
  • dest - ранг адресата;
  • sendtag - тег передаваемого сообщения;
  • source - ранг источника;
  • recvtag - тег принимаемого сообщения;
  • comm - коммуникатор.

Выходные параметры:

  • buf - начальный адрес буфера приема и передачи;
  • status - статус.

Принимаемое сообщение не должно превышать по размеру отправляемое сообщение, а передаваемые и принимаемые данные должны быть одного типа. Последовательность приема и передачи выбирается системой автоматически.

Инициализация неблокирующей стандартной передачи

int MPI_Isend(void *buf,  int count, MPI_Datatype datatype,  
	int dest, int tag, MPI_Comm comm, MPI_Request *request)
MPI_ISEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, REQUEST, IERR)

Входные параметры этой подпрограммы аналогичны аргументам подпрограммы MPI_Send.

Выходной параметр:

  • request - идентификатор операции.

Инициализация неблокирующей синхронной передачи данных

int MPI_Issend(void *buf, int count, MPI_Datatype datatype, 
	int dest, int tag, MPI_Comm comm, MPI_Request *request)

MPI_ISSEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, REQUEST, IERR)

Параметры этой подпрограммы совпадают с параметрами подпрограммы MPI_Send.

Неблокирующая буферизованная передача сообщения

int MPI_Ibsend(void *buf, int count, MPI_Datatype datatype, int dest, 
	int tag, MPI_Comm comm, MPI_Request *request)

MPI_IBSEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, REQUEST, IERR)

Неблокирующая передача "по готовности"

int MPI_Irsend(void* buf, int count, MPI_Datatype datatype, int dest, 
	int tag, MPI_Comm comm, MPI_Request *request)

MPI_IRSEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, REQUEST, IERR)

Параметры всех подпрограмм неблокирующей передачи совпадают.

Инициализация неблокирующего приема

int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, 
int tag, MPI_Comm comm, MPI_Request *request)

MPI_IRECV(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM, REQUEST, IERR)

Назначение аргументов здесь такое же, как и в предыдущих подпрограммах, за исключением того, что указывается ранг не адресата, а источника сообщения ( source ).

Блокировка работы процесса до завершения приема или передачи сообщения

int MPI_Wait(MPI_Request *request, MPI_Status *status)
MPI_WAIT(REQUEST, STATUS, IERR)

Входной параметр:

  • request - идентификатор операции обмена.

Выходной параметр:

  • status - статус выполненной операции.

Значение статуса для операции передачи сообщения можно получить вызовом подпрограммы MPI_Test_cancelled. Можно вызвать MPI_Wait с пустым или неактивным аргументом request. В этом случае операция завершается сразу же с пустым статусом.

Успешное выполнение подпрограммы MPI_Wait после вызова MPI_Ibsend подразумевает, что буфер передачи можно использовать вновь, то есть пересылаемые данные отправлены или скопированы в буфер, выделенный при вызове подпрограммы MPI_Buffer_attach. В этот момент уже нельзя отменить передачу. Если не будет зарегистрирован соответствующий прием, буфер нельзя будет освободить. В этом случае можно применить подпрограмму MPI_Cancel, которая освобождает память, выделенную подсистеме коммуникаций.

Неблокирующая проверка завершения приема или передачи сообщения

int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status)

MPI_TEST(REQUEST, FLAG, STATUS, IERR)

Входной параметр:

  • request - идентификатор операции обмена.

Выходные параметры:

  • flag - "истина", если операция, заданная идентификатором request, выполнена;
  • status - статус выполненной операции.

Если при вызове MPI_Test используется пустой или неактивный аргумент request, операция возвращает значение флага "истина" и пустой статус.

Проверка завершения всех обменов

int MPI_Waitall(int count, MPI_Request requests[], MPI_Status statuses [ ])
MPI_WAITALL(COUNT, REQUESTS, STATUSES, IERR)

Выполнение процесса блокируется до тех пор, пока все операции обмена, связанные с активными запросами в массиве requests, не будут выполнены. Возвращается статус этих операций. Статус обменов содержится в массиве statuses. count - количество запросов на обмен (размер массивов requests и statuses ).

В результате выполнения подпрограммы MPI_Waitall запросы, сформированные неблокирующими операциями обмена, аннулируются, а соответствующим элементам массива присваивается значение MPI_REQUEST_NULL. Список может содержать пустые или неактивные запросы. Для каждого из них устанавливается пустое значение статуса.

В случае неуспешного выполнения одной или более операций обмена подпрограмма MPI_Waitall возвращает код ошибки MPI_ERR_IN_STATUS и присваивает полю ошибки статуса значение кода ошибки соответствующей операции. Если операция выполнена успешно, полю присваивается значение MPI_SUCCESS, а если не выполнена, но и не было ошибки - значение MPI_ERR_PENDING. Последний случай соответствует наличию запросов на выполнение операции обмена, ожидающих обработки.

Неблокирующая проверка завершения обменов

int MPI_Testall(int count, MPI_Request requests[], int *flag, MPI_Status statuses[])
MPI_TESTALL(COUNT, REQUESTS, FLAG, STATUSES, IERR)

При вызове возвращается значение флага ( flag ) "истина", если все обмены, связанные с активными запросами в массиве requests, выполнены. Если завершены не все обмены, флагу присваивается значение "ложь", а массив statuses не определен. count - количество запросов.

Каждому статусу, соответствующему активному запросу, присваивается значение статуса соответствующего обмена. Если запрос был сформирован операцией неблокирующего обмена, он аннулируется, а соответствующему элементу массива присваивается значение MPI_REQUEST_NULL. Каждому статусу, соответствующему пустому или неактивному запросу, присваивается пустое значение.

Блокирующая проверка завершения любого числа обменов

int MPI_Waitany(int count, MPI_Request requests[], int *index, MPI_Status *status)

MPI_WAITANY(COUNT, REQUESTS, INDEX, STATUS, IERR)

Выполнение процесса блокируется до тех пор, пока, по крайней мере, один обмен из массива запросов ( requests ) не будет завершен.

Входные параметры:

  • requests - запрос;
  • count - количество элементов в массиве requests, а выходные: status и index .

Выходные параметры:

  • index - индекс запроса (в языке C это целое число от 0 до count - 1, а в языке FORTRAN от 1 до count ) в массиве requests ;
  • status - статус.

Если запрос на выполнение операции был сформирован неблокирующей операцией обмена, он аннулируется и ему присваивается значение MPI_REQUEST_NULL. Массив запросов может содержать пустые или неактивные запросы. Если в списке вообще нет активных запросов или он пуст, вызовы завершаются сразу со значением индекса MPI_UNDEFINED и пустым статусом.

Проверка выполнения любого ранее инициализированного обмена

int MPI_Testany(int count, MPI_Request requests[],  int *index, 
	int *flag, MPI_Status *status)
MPI_TESTANY(COUNT, REQUESTS, INDEX, FLAG, STATUS, IERR)

Смысл и назначение параметров этой подпрограммы те же, что и для подпрограммы MPI_Waitany. Дополнительный аргумент flag, который принимает значение "истина", если одна из операций завершена. Блокирующая подпрограмма MPI_Waitany и неблокирующая MPI_Testany взаимозаменяемы, впрочем, как и другие аналогичные пары.

Подпрограммы MPI_Waitsome и MPI_Testsome действуют аналогично подпрограммам MPI_Waitany и MPI_Testany, кроме случая, когда завершается более одного обмена. В подпрограммах MPI_Waitany и MPI_Testany обмен из числа завершенных выбирается произвольно, именно для него и возвращается статус, а для MPI_Waitsome и MPI_Testsome статус возвращается для всех завершенных обменов. Эти подпрограммы можно использовать для определения, сколько обменов завершено:

int MPI_Waitsome(int incount, MPI_Request requests[],  int *outcount, 
	int indices[], MPI_Status statuses[])
MPI_WAITSOME(INCOUNT, REQUESTS, OUTCOUNT, INDICES, STATUSES, IERR)

Здесь incount - количество запросов. В outcount возвращается количество выполненных запросов из массива requests, а в первых outcount элементах массива indices возвращаются индексы этих операций. В первых outcount элементах массива statuses возвращается статус завершенных операций. Если выполненный запрос был сформирован неблокирующей операцией обмена, он аннулируется. Если в списке нет активных запросов, выполнение подпрограммы завершается сразу, а параметру outcount присваивается значение MPI_UNDEFINED.

Неблокирующая проверка выполнения обменов

int MPI_Testsome(int incount, MPI_Request requests[],  int *outcount, 
	int indices[], MPI_Status statuses[])

MPI_TESTSOME(INCOUNT, REQUESTS, OUTCOUNT, INDICES, STATUSES, IERR)

Параметры такие же, как и у подпрограммы MPI_Waitsome. Эффективность подпрограммы MPI_Testsome выше, чем у MPI_Testany, поскольку первая возвращает информацию обо всех операциях, а для второй требуется новый вызов для каждой выполненной операции.

Запрос для стандартной передачи создается при вызове подпрограммы MPI_Send_init:

int MPI_Send_init(void *buf,  int count, MPI_Datatype datatype, 
	int dest,  int tag, MPI_Comm comm, MPI_Request *request)

MPI_SEND_INIT(BUF, COUNT, DATATYPE, DEST, TAG, COMM, REQUEST, IERR)

Входные параметры:

  • buf - адрес буфера передачи;
  • count - количество элементов;
  • datatype - тип элементов;
  • dest - ранг адресата;
  • tag - тег сообщения;
  • comm - коммуникатор.

Выходной параметр:

  • request - запрос на выполнение операции обмена.

Инициализация отложенного обмена

int MPI_Start(MPI_Request *request)
MPI_START(REQUEST, IERR)

Входной параметр:

  • request - запрос на выполнение операции обмена.

Вызов MPI_Start с запросом на обмен, созданным MPI_Send_init, инициирует обмен с теми же свойствами, что и вызов подпрограммы MPI_Isend, а вызов MPI_Start с запросом, созданным MPI_Bsend_init, инициирует обмен аналогично вызову MPI_Ibsend. Сообщение, которое передано операцией, инициированной с помощью MPI_Start, может быть принято любой подпрограммой приема.

Инициализация обменов, связанных с запросами на выполнение неблокирующей операции обмена в массиве requests

int MPI_Startall(int count, MPI_request *requests)

MPI_STARTALL(COUNT, REQUESTS, IERR)

Аннулирование неблокирующих "ждущих" (ожидающих обработки) обменов

int MPI_Cancel(MPI_request *request)

MPI_CANCEL(REQUEST, IERR)

MPI_Cancel можно использовать для аннулирования обменов, использующих как отложенный, так и обычный запрос. После вызова MPI_Cancel и следующего за ним вызова MPI_Wait или MPI_Test, запрос на выполнение операции обмена становится неактивным и может быть активизирован для нового обмена. Информация об аннулированной операции содержится в аргументе status.

Проверка, произведено ли аннулирование обмена, связанного с указанным статусом

int MPI_Test_cancelled(MPI_Status *status,  int *flag)

MPI_TEST_CANCELLED(STATUS, FLAG, IERR)

Аннулирование запроса на выполнение операции (request)

int MPI_Request_free(MPI_Request *request)

MPI_REQUEST_FREE(REQUEST, IERR)

При вызове помечает запрос на обмен для удаления и присваивает ему значение MPI_REQUEST_NULL. Операции обмена, связанной с этим запросом, дается возможность завершиться, а сам запрос удаляется только после завершения обмена.