Интерфейс передачи сообщений MPI
Двухточечный обмен
Участниками двухточечного обмена являются два процесса: процесс-отправитель и процесс-получатель (рис. 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. Операции обмена, связанной с этим запросом, дается возможность завершиться, а сам запрос удаляется только после завершения обмена.