Интерфейс передачи сообщений MPI
Далее приводится описание свободно распространяемой версии MPI - MPICH 1.2.7, соответствующей спецификации MPI 1.
Модель параллельной программы в MPI
В модели программирования MPI параллельная программа при запуске порождает несколько процессов, взаимодействующих между собой с помощью сообщений. Совокупность всех процессов, составляющих параллельное приложение, или их части, описывается специальной структурой, которая называется коммуникатором (областью взаимодействия).
Каждому процессу в области взаимодействия назначается уникальный числовой идентификатор - ранг,значение которого от 0 до np - 1 ( np - число процессов). Ранги, назначаемые одному и тому же процессу в разных коммуникаторах, вообще говоря, различны.
Структура программы, написанной по схеме хозяин/работник, приведена ниже.
program para ... if (ранг процесса = рангу мастер-процесса) then код мастер-процесса else код подчиненного процесса (подчиненных процессов) endif end
Каждый экземпляр программы уже в процессе своего выполнения определяет, является ли он мастер-процессом. Затем, в зависимости от результата этой проверки, выполняется одна из ветвей условного оператора. Первая ветвь соответствует мастер-задаче, а вторая - подчиненной задаче. Способы взаимодействия между подзадачами определяются программистом.
Перед использованием процедур передачи сообщений программа должна подключиться к системе обмена сообщениями. Подключение выполняется с помощью соответствующего вызова процедуры из библиотеки. В одних реализациях модели допускается только одно подключение, а в других - несколько подключений к системе.
Сообщения
Сообщение содержит пересылаемые данные и служебную информацию. Для того, чтобы передать сообщение, необходимо указать:
- ранг процесса-отправителя сообщения;
- адрес, по которому размещаются пересылаемые данные процесса-отправителя;
- тип пересылаемых данных;
- количество данных;
- ранг процесса, который должен получить сообщение;
- адрес, по которому должны быть размещены данные процессом-получателем.
- тег сообщения;
- идентификатор коммуникатора, описывающего область взаимодействия, внутри которой происходит обмен.
Тег - это задаваемое пользователем целое число от 0 до 32767, которое играет роль идентификатора сообщения и позволяет различать сообщения, приходящие от одного процесса. Теги могут использоваться и для соблюдения определенного порядка приема сообщений.
Прием сообщения начинается с подготовки буфера достаточного размера. В этот буфер записываются принимаемые данные. Операция отправки или приема сообщения считается завершенной, если программа может вновь использовать буферы сообщений.
Разновидности обменов сообщениями
В MPI реализованы разные виды обменов. Прежде всего, это двухточечные (задействованы только два процесса) и коллективные (задействованы более двух процессов).
Двухточечные обмены используются для организации локальных и неструктурированных коммуникаций.
При выполнении глобальных операций используются коллективные обмены. Асинхронные коммуникации реализуются с помощью запросов о получении сообщений. Имеется несколько разновидностей двухточечного обмена.
- Блокирующие прием/передача - приостанавливают выполнение процесса на время приема сообщения.
- Неблокирующие прием/передача - выполнение процесса продолжается в фоновом режиме, а программа в нужный момент может запросить подтверждение завершения приема сообщения.
- Синхронный обмен - сопровождается уведомлением об окончании приема сообщения.
- Асинхронный обмен - уведомлением не сопровождается.
Привязка к языку Fortran
Имена подпрограмм и констант MPI в программах на языке Fortran начинаются с MPI _. При вызове подпрограмм коды завершения передаются через дополнительный параметр целого типа (находится на последнем месте в списке параметров подпрограммы). Код успешного завершения - MPI_SUCCESS. Константы и другие объекты MPI описываются в файле mpif.h, который включается в MPI -программу с помощью оператора include.
В некоторых подпрограммах используется переменная status, которая является массивом стандартного целого типа. Его размер MPI_STATUS_SIZE.
При обращении к подпрограммам MPI используются типы данных MPI, для большинства из которых имеется соответствие базовым типам языка (см. табл. 3.1)
Типы MPI_Datatype и MPI_Comm - эмулируются стандартным целым типом языка Fortran (Integer).
В программах на языке C используются библиотечные функции MPI, в программах на языке Fortran - процедуры.
Привязка к языку C
В программах на языке C имена подпрограмм имеют вид Класс_действие_подмножество или Класс_действие. В C++ подпрограмма является методом для определенного класса, имя имеет в этом случае вид MPI::Класс::действие_подмножество. Для некоторых действий введены стандартные наименования: Create - создание нового объекта, Get - получение информации об объекте, Set - установка параметров объекта, Delete - удаление информации, Is - запрос о том, имеет ли объект указанное свойство.
Имена констант MPI записываются в верхнем регистре. Их описания находятся в заголовочном файле mpi.h.
Входные параметры функций передаются по значению, а выходные (и INOUT ) - по ссылке. Соответствие типов MPI стандартным типам языка C приведено в табл. 3.2.
Коды завершения
В MPI приняты стандартные соглашения о кодах завершения вызовов подпрограмм. Так, например, возвращаются значения MPI_SUCCESS - при успешном завершении вызова и MPI_ERR_OTHER - обычно при попытке повторного вызова процедуры MPI_Init.
Вместо числовых кодов в программах обычно используют специальные именованные константы:
- MPI_ERR_BUFFER - неправильный указатель на буфер;
- MPI_ERR_COMM - неправильный коммуникатор;
- MPI_ERR_RANK - неправильный ранг;
- MPI_ERR_OP - неправильная операция;
- MPI_ERR_ARG - неправильный аргумент;
- MPI_ERR_UNKNOWN - неизвестная ошибка;
- MPI_ERR_TRUNCATE - сообщение обрезано при приеме;
- MPI_ERR_INTERN - внутренняя ошибка. Обычно возникает, если системе не хватает памяти.
Тип данных MPI | Тип данных C |
---|---|
MPI_CHAR | Signed char |
MPI_SHORT | Signed short int |
MPI_INT | Signed int |
MPI_LONG | Signed long int |
MPI_UN SIGNE D_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 |
MPI_BYTE | Нет соответствия |
MPI_PACKED | Нет соответствия |
Основные понятия MPI
Коммуникатор представляет собой структуру, содержащую либо все процессы, исполняющиеся в рамках данного приложения, либо их подмножество. Процессы, принадлежащие одному и тому же коммуникатору, наделяются общим контекстом обмена. Операции обмена возможны только между процессами, связанными с общим контекстом, то есть, принадлежащие одному и тому же коммуникатору (рис. 3.1). Каждому коммуникатору присваивается идентификатор. В MPI есть несколько стандартных коммуникаторов:
- MPI_COMM_WORLD - включает все процессы параллельной программы;
- MPI_COMM_SELF - включает только данный процесс;
- MPI_COMM_NULL - пустой коммуникатор, не содержит ни одного процесса.
В MPI имеются процедуры, позволяющие создавать новые коммуникаторы, содержащие подмножества процессов.
Ранг процесса представляет собой уникальный числовой идентификатор, назначаемый процессу в том или ином коммуникаторе. Ранги в разных коммуникаторах назначаются независимо и имеют целое значение от 0 до число_процессов - 1 (рис. 3.2).
Тег (маркер) сообщения - это уникальный числовой идентификатор, который назначается сообщению и позволяет различать сообщения, если в этом есть необходимость. Если тег не требуется, вместо него можно использовать "джокер" MPI_ANY_TAG.
Типовая структура MPI -программы:
program para ... if (process = master) then master clause else slave clause endif end
Различные подпрограммы MPI
Подключение к MPI
int MPI_Init(int *argc, char **argv) MPI_INIT(IERR)
Аргументы argc и argv требуются только в программах на C, где они задают количество аргументов командной строки запуска программы и вектор этих аргументов. Данный вызов предшествует всем прочим вызовам подпрограмм MPI.
Завершение работы с MPI
p>int MPI_Finalize() MPI_FINALIZE(IERR)
После вызова данной подпрограммы нельзя вызывать подпрограммы MPI. MPI_FINALIZE должны вызывать все процессы перед завершением своей работы.
Определение размера области взаимодействия
p>int MPI_Comm_size(MPI_Comm comm, int *size) MPI_COMM_SIZE(COMM., SIZE, IERR)
Входные параметры:
- comm - коммуникатор.
Выходные параметры:
- size - количество процессов в области взаимодействия.
Определение ранга процесса
int MPI_Comm_rank(MPI_Comm comm, int *rank) MPI_COMM_RANK(COMM, RANK, IERR)
Входные параметры:
- comm- коммуникатор.
Выходные параметры:
- rank - ранг процесса в области взаимодействия.
Определение имени узла, на котором выполняется данный процесс
MPI_Get_processor_name(char *name, int *resultlen) MPI_GET_PROCESSOR_NAME(NAME, RESULTLEN, IERR)
Выходные параметры:
- name - идентификатор вычислительного узла. Массив не менее чем из MPI_MAX_PROCESSOR_NAME элементов;
- resultlen - длина имени.
Время, прошедшее с произвольного момента в прошлом
double MPI_Wtime() MPI_WTIME(TIME, IERR)