Руководство по MPI (547935), страница 3
Текст из файла (страница 3)
Процедура MPI_TestSome
Формат процедуры:
int MPI_TestSome(int incount, MPI_Request *requests, int *outcount, int *indexes, MPI_Status *statuses), где
-
incount - число идентификаторов;
-
requests - массив идентификаторов асинхронного приема или передачи;
-
OUT outcount - число идентификаторов завершившихся операций обмена;
-
OUT indexes - массив номеров завершившихся операций обмена;
-
OUT statuses - параметры завершившихся операций.
Данная процедура работает так же, как и MPI_TestAny, за исключением того, что возврат происходит немедленно. Если ни одна из указанных операций не завершилась, то значение outcount будет равно нулю.
Процедура MPI_Iprobe
Формат процедуры:
int MPI_Iprobe( int source, int msgtag, MPI_Comm comm, int *flag, MPI_Status *status), где
-
source - номер процесса-отправителя или MPI_ANY_SOURCE;
-
msgtag - идентификатор ожидаемого сообщения или MPI_ANY_TAG;
-
comm - идентификатор группы;
-
OUT flag - признак завершенности операции обмена;
-
OUT status - параметры обнаруженного сообщения.
Данная процедура обеспечивает получение информации о поступлении и структуре ожидаемого сообщения без блокировки. В параметр flag возвращается знаачение 1, если сообщение с подходящими атрибутами уже может быть принято (в этом случае ее действие полностью аналогично MPI_Probe), и значение 0, если сообщения с указанными атрибутами еще нет.
Для снижения накладных расходов, возникающих в рамках одного процессора при обработке приема/передачи и перемещении необходимой информации между процессом и сетевым контроллером, могут использоваться процедуры: MPI_Send_Init, MPI_Recv_Init и MPI_Start_All. Несколько запросов на прием и/или передачу могут объеди-няться вместе для того, чтобы далее их можно было бы запустить одной командой. Способ приема сообщения никак не зависит от способа его посылки: сообщение, отправленное с помощью объединения запросов либо обычным способом, может быть принято как обычным способом, так и с помощью объединения запросов.
Процедура MPI_Send_Init
Формат процедуры:
int MPI_Send_Init(void *buf, int count, MPI_Datatype datatype, int dest, int msgtag, MPI_Comm comm, MPI_Request *request), где
-
buf - адрес начала буфера посылки сообщения;
-
count - число передаваемых элементов в сообщении;
-
datatype - тип передаваемых элементов;
-
dest - номер процесса-получателя;
-
msgtag - идентификатор сообщения;
-
comm - идентификатор группы;
-
OUT request - идентификатор асинхронной передачи.
Данная процедура обеспечивает формирование запроса на выполнение пересылки данных. Все параметры точно такие же, как и у подпрограммы MPI_ISend, однако в отличие от нее пересылка не начинается до вызова подпрограммы MPI_StartAll.
Процедура MPI_Recv_Init
Формат процедуры:
int MPI_Recv_Init(void *buf, int count, MPI_Datatype datatype, int source, int msgtag, MPI_Comm comm, MPI_Request *request), где
-
OUT buf - адрес начала буфера приема сообщения;
-
count - число принимаемых элементов в сообщении;
-
datatype - тип принимаемых элементов;
-
source - номер процесса-отправителя;
-
msgtag - идентификатор сообщения;
-
comm - идентификатор группы;
-
OUT request - идентификатор асинхронного приема.
Данная процедура обеспечивает формирование запроса на выполнение приема данных. Все параметры точно такие же, как и у подпрограммы MPI_IReceive, однако в отличие от нее реальный прием не начинается до вызова подпрограммы MPI_StartAll.
Процедура MPI_Start_All
Формат процедуры:
int MPI_Start_All (int count, MPI_Request *requests), где
-
count - число запросов на взаимодействие;
-
OUT requests - массив идентификаторов приема/передачи.
Данная процедура обеспечивает запуск всех отложенных взаимодействий, ассоциированных вызовами подпрограмм MPI_Send_Init и MPI_Recv_Init с элементами массива запросов requests. Все взаимодействия запускаются в режиме без блокировки, а их завершение можно определить обычным образом с помощью процедур MPI_Wait и MPI_Test.
Процедура MPI_Sendrecv
Формат процедуры:
int MPI_Sendrecv(void *sbuf, int scount, MPI_Datatype stype, int dest, int stag, void *rbuf, int rcount, MPI_Datatype rtype, int source, MPI_DAtatype rtag, MPI_Comm comm, MPI_Status *status), где
-
sbuf - адрес начала буфера посылки сообщения;
-
scount - число передаваемых элементов в сообщении;
-
stype - тип передаваемых элементов;
-
dest - номер процесса-получателя;
-
stag - идентификатор посылаемого сообщения;
-
OUT rbuf - адрес начала буфера приема сообщения;
-
rcount - число принимаемых элементов сообщения;
-
rtype - тип принимаемых элементов;
-
source - номер процесса-отправителя;
-
rtag - идентификатор принимаемого сообщения;
-
comm - идентификатор группы;
-
OUT status - параметры принятого сообщения.
Данная процедура объединяет в едином запросе посылку и прием сообщений. Принимающий и отправляющий процессы могут являться одним и тем же процессом. Сообщение, отправленное операцией MPI_Sendrecv, может быть принято обычным образом, и точно также операция MPI_Sendrecv может принять сообщение, отправленное обычной операцией MPI_Send. Буфера приема и посылки обязательно должны быть различными.
-
Процедуры коллективного взаимодействия процессов
Для коллективного взаимодействия процессов используются процедуры MPI_Bcast, MPI_Gather, MPI_AllReduce и MPI_Reduce. В процессе коллективного взаимодействия участвуют все процессы приложения. Соответствующая процедура должна быть вызвана каждым процессом, быть может, со своим набором параметров. Возврат из процедуры коллективного взаимодействия может произойти в тот момент, когда участие процесса в данной операции уже закончено. Как и для блокирующих процедур, возврат означает то, что разрешен свободный доступ к буферу приема или посылки, но не означает ни того, что операция завершена другими процессами, ни даже того, что она ими начата (если это возможно по смыслу операции).
Процедура MPI_Bcast
Формат процедуры:
int MPI_Bcast (void *buf, int count, MPI_Datatype datatype, int source, MPI_Comm comm), где
-
OUT buf - адрес начала буфера посылки сообщения;
-
count - число передаваемых элементов в сообщении;
-
datatype - тип передаваемых элементов;
-
source - номер рассылающего процесса;
-
comm - идентификатор группы.
Процедура обеспечивает рассылку сообщения от процесса source всем процессам, включая рассылающий процесс. При возврате из процедуры содержимое буфера buf процесса source будет скопировано в локальный буфер процесса. Значения параметров count, datatype и source должны быть одинаковыми у всех процессов.
Процедура MPI_Gather.
Формат процедуры:
int MPI_Gather(void *sbuf, int scount, MPI_Datatype stype, void *rbuf, int rcount, MPI_Datatype rtype, int dest, MPI_Comm comm), где
-
sbuf - адрес начала буфера посылки;
-
scount - число элементов в посылаемом сообщении;
-
stype - тип элементов отсылаемого сообщения;
-
OUT rbuf - адрес начала буфера сборки данных;
-
rcount - число элементов в принимаемом сообщении;
-
rtype - тип элементов принимаемого сообщения;
-
dest - номер процесса, на котором происходит сборка данных;
-
comm - идентификатор группы;
-
OUT ierror - код ошибки.
Данная процедура обеспечивает сбор данных со всех процессов в буфере rbuf процесса dest. Каждый процесс, включая dest, посылает содержимое своего буфера sbuf процессу dest. Собирающий процесс сохраняет данные в буфере rbuf, располагая их в порядке возрастания номеров процессов. Параметр rbuf имеет значение только на собирающем процессе и на остальных игнорируется, значения параметров count, datatype и dest должны быть одинаковыми у всех процессов.
Процедура MPI_AllReduce
Формат процедуры:
int MPI_AllReduce(void *sbuf, void *rbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm), где
-
sbuf - адрес начала буфера для аргументов;
-
OUT rbuf - адрес начала буфера для результата;
-
count - число аргументов у каждого процесса;
-
datatype - тип аргументов;
-
op - идентификатор глобальной операции;
-
comm - идентификатор группы.
Процедура обеспечивает выполнение count глобальных операций op с возвратом count результатов во всех процессах в буфере rbuf. Операция выполняется независимо над соответствующими аргументами всех процессов. Значения параметров count и datatype у всех процессов должны быть одинаковыми. Из соображений эффективности реализации предполагается, что операция op обладает свойствами ассоциативности и коммутативности.
Процедура MPI_Reduce.
Формат процедуры:
int MPI_Reduce(void *sbuf, void *rbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm), где
-
sbuf - адрес начала буфера для аргументов;
-
OUT rbuf - адрес начала буфера для результата;
-
count - число аргументов у каждого процесса;
-
datatype - тип аргументов;
-
op - идентификатор глобальной операции;
-
root - процесс-получатель результата;
-
comm - идентификатор группы.
Процедура аналогична предыдущей, но результат будет записан в буфер rbuf только у процесса root.
3.5 Процедура синхронизации процессов
Процедура синхронизации процессов блокирует работу процессов, вызвавших данную процедуру, до тех пор, пока все оставшиеся процессы группы comm также не выполнят эту процедуру.
Процедура MPI_Barrier
Формат процедуры:
int MPI_Barrier(MPI_Comm comm), где comm - идентификатор группы.
3.6 Процедуры для работы с группами процессов
Процессы объединяются в группы; могут быть вложенные группы. Внутри группы все процессы пронумерованы. С каждой группой ассоциирован свой коммуникатор. Поэтому при осуществлении пересылки необходимо указать идентификатор группы, внутри которой производится эта пересылка. Все процессы содержатся в группе с предопределенным идентификатором MPI_COMM_WORLD.
Процедуры, предназначенные для работы с группами процессов, обеспечивают создание и удаление групп (коммуникаторов), а также разбиение групп на подгруппы.
Процедура MPI_Comm_Split
Формат процедуры:
int MPI_Comm_Split(MPI_Comm comm, int color, int key, MPI_Comm *newcomm), где
-
comm - идентификатор группы;
-
color - признак разделения на группы;
-
key - параметр, определяющий нумерацию в новых группах;
-
OUT newcomm - идентификатор новой группы.
Данная процедура разбивает все множество процессов, входящих в группу comm, на непересекающиеся подгруппы - одну подгруппу на каждое значение параметра color (неотрицательное число). Каждая новая подгруппа содержит все процессы одного цвета. Если в качестве color указано значение MPI_UNDEFINED, то в newcomm будет возвращено значение MPI_COMM_NULL.
Процедура MPI_Comm_Free
Формат процедуры:
int MPI_Comm_Free(MPI_Comm comm),
где OUT comm - идентификатор группы.
Процедура уничтожает группу, ассоциированную с идентификатором comm, который после возвращения устанавливается в MPI_COMM_NULL.
3.7 Предопределенные константы и типы данных
В стандарте MPI существует несколько предопределенных типов, среди них:
-
MPI_Status - структура; атрибуты сообщений; содержит три обязательных поля:
-
MPI_Source (номер процесса отправителя);
-
MPI_Tag (идентификатор сообщения – целое неотрицательное число, лежащее в диапазоне от 0 до 32767.);
-
MPI_Error (код ошибки);
-
MPI_Request - системный тип; идентификатор операции посылки-приема сообщения;
-
MPI_Comm - системный тип; идентификатор группы (коммуникатора);
-
MPI_COMM_WORLD - зарезервированный идентификатор группы, состоящей их всех процессов приложения.
Предопределенные константы типа элементов сообщений используются для указания типа пересылаемых данных в процедурах группы приема/передачи. Данные константы представлены в Таблице 1.
Таблица 1
Константы MPI | Тип в C |
MPI_CHAR | signed char |
MPI_SHORT | signed int |
MPI_INT | signed int |
MPI_LONG | signed long int |
MPI_UNSIGNED_CHAR | unsigned char |
MPI_UNSIGNED_SHORT | unsigned int |
MPI_UNSIGNED | unsigned int |
MPI_UNSIGNED_LONG | unsigned long int |
MPI_FLOAT | float |
MPI_DOUBLE | double |
MPI_LONG_DOUBLE | long double |
Более подробно о правилах написания параллельных программ, а также синтаксис процедур MPI можно найти в книге “Writing Message-Passing Parallel Programs with MPI” [6].
С одной стороны, мы передаем в MPI_Recv номер задачи, от которой ждем сообщение, и его идентификатор; а с другой - получаем их от MPI в структуре status? Это сделано потому, что MPI_Recv может быть вызвана с аргументами-джокерами ("принимай что угодно/от кого угодно"), и после такого приема данных программа узнает фактические номер/идентификатор, читая поля MPI_SOURCE и MPI_TAG из структуры status.
Поле MPI_ERROR, как правило, проверять необязательно - обработчик ошибок, устанавливаемый MPI по умолчанию, в случае сбоя завершит выполнение программы до возврата из MPI_Recv. Таким образом, после возврата из MPI_Recv поле status.MPI_ERROR может быть равно только 0 (или, если угодно, MPI_SUCCESS);
Тип MPI_Status не содержит поля, в которое записывалась бы фактическая длина пришедшего сообщения. Длину можно узнать так: