Следующие пункты обычно используемых параметров для команды mpirun

-np определяет число задач на выполнение

-wd определяет рабочую директорию для использования процессом MPI. Это необходимо только тогда, когда текущая директория и желаемая рабочая директория не совпадают.

-h | -help показывает аргументы командной строки для mpirun

-mpi_debug включает дополнительную проверку на входные параметры и дополнительный выход если ошибки возникнут при выполнении.

Хотя MPI обеспечивает расширенное множество вызовов, функциональная программа на MPI может быть записана с помощью всего шести базовых вызова:

MPI_Init

MPI_Comm_rank

MPI_Comm_size

MPI_Send

MPI_Recv

MPI_Finalize

Для удобства программирования и оптимизации кода, вам следует рассмотреть использование других вызовов, таких как описано в модулях по попарной и коллективной коммуникациям.

Сообщения MPI

Сообщения MPI состоят из двух частей:

данные (старт буфера, число, тип данных)

оболочка (назначение/источник, тег, коммуникатор)

Данные определяют информацию, которая будет отослана или получена. Оболочка (конверт) используется в маршрутизации сообщения к получателю и связывает вызовы отправки с вызовами получения.

Коммуникаторы

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

Все дополнительные объекты: имена функций, константы, предопределенные типы данных и т.п., используемые в MPI, имеют префикс MPI_. Если пользова­тель не будет использовать в программе имен с таким префиксом, то конфлик­тов с объектами MPI заведомо не будет. Все описания интерфейса MPI собраны в файле mpi.h, поэтому в начале MPI-программы должна стоять директива

#include <mpi.h>

MPI-программа — это множество параллельных взаимодействующих процес­сов. Все процессы порождаются один раз, образуя параллельную часть про­граммы. В ходе выполнения MPI-программы порождение дополнительных процессов или уничтожение существующих не допускается. Каждый процесс работает в своем адресном пространстве, никаких общих переменных или дан­ных в MPI нет. Основным способом взаимодействия между процессами являет­ся явная посылка сообщений.

Для локализации взаимодействия параллельных процессов программы можно создавать группы процессов, предоставляя им отдельную среду для общения — коммуникатор. Состав образуемых групп произволен. Группы могут полно­стью входить одна в другую, не пересекаться или пересекаться частично. При старте программы всегда считается, что все порожденные процессы работают в рамках всеобъемлющего коммуникатора, имеющего предопределенное имя mpi_comm_world. Этот коммуникатор существует всегда и служит для взаимо­действия всех процессов MPI-программы.

Каждый процесс MPI-программы имеет уникальный атрибут номер процесса, который является целым неотрицательным числом. С помощью этого атрибута происходит значительная часть взаимодействия процессов между собой. Ясно, что в одном и том же коммуникаторе все процессы имеют различные номера. Но поскольку процесс может одновременно входить в разные коммуникаторы, то его номер в одном коммуникаторе может отличаться от его номера в другом. Отсюда становятся понятными два основныю атрибута процесса: коммуника­тор и номер в коммуникаторе. Если группа содержит n процессов, то номер любого процесса в данной группе лежит в пределах от 0 до n - 1.

Основным способом общения процессов между собой является посылка сооб­щений. Сообщение — это набор данных некоторого типа. Каждое сообщение имеет несколько атрибутов, в частности, номер процесса-отправителя, номер процесса-получателя, идентификатор сообщения и другие. Одним из важных атрибутов сообщения является его идентификатор или тэг. По идентификатору процесс, принимающий сообщение, например, может различить два сообщения, пришедшие к нему от одного и того же процесса. Сам идентификатор сообще­ния является целым неотрицательным числом, лежащим в диапазоне от 0 до 32767. Для работы с атрибутами сообщений введена структура MPI_Status, по­ля которой дают доступ к их значениям.

Общие функции MPI

Прежде чем переходить к описанию конкретных функций, сделаем несколько общих замечаний. При описании функций мы всегда будем пользоваться сло­вом OUT для обозначения выходных параметров, через которые функция возвра­щает результаты. Даже если результатом работы функции является одно число, оно будет возвращено через один из параметров. Связано это с тем, что практи­чески все функции MPI возвращают в качестве своего значения информацию об успешности завершения. В случае успешного выполнения функция вернет зна­чение MPI_SUCCESS, иначе — код ошибки. Вид ошибки, которая произошла при выполнении функции, можно будет понять из описания каждой функции. Пре­допределенные возвращаемые значения, соответствующие различным ошибоч­ным ситуациям, определены в файле mpi.h. В дальнейшем при описании кон­кретных функций, если ничего специально не сказано, то возвращаемое функ­цией значение будет подчиняться именно этому правилу.

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

int MPI_Init(int *argc, char ***argv)

Инициализация параллельной части программы. Все другие функции MPI мо­гут быть вызваны только после вызова MPI_Init. Необычный тип аргументов MPI_Init предусмотрен для того, чтобы иметь возможность передать всем про­цессам аргументы функции main. Инициализация параллельной части для каж­дого приложения должна выполняться только один раз.

int MPI_Finalize(void)

Завершение параллельной части приложения. Все последующие обращения к любым MPI-функциям, в том числе к MPI_Init, запрещены. К моменту вызова MPI_Finalize каждым процессом программы все действия, требующие его уча­стия в обмене сообщениями, должны быть завершены.

Общая схема MPI-программы выглядит так:

main(int argc, char **argv)

{

MPI_Init(&argc, &argv);

MPI_Finalize();

}

int MPI_Comm_size(MPI_Comm comm, int *size)

• comm — идентификатор коммуникатора,

• out size — число процессов в коммуникаторе comm.

Определение общего числа параллельных процессов в коммуникаторе comm. Ре­зультат возвращается через параметр size, для чего функции передается адрес этой переменной. Поскольку коммуникатор является сложной структурой, пе­ред ним стоит имя предопределенного типа MPI_Comm, определенного в файле mpi.h.

int MPI_Comm_rank(MPI_Comm comm, int *rank)

• comm — идентификатор коммуникатора,

• out rank — номер процесса в коммуникаторе comm.

Определение номера процесса в коммуникаторе comm. Если функция MPI_Comm_size для того же коммуникатора comm вернула значение size, то зна­чение, возвращаемое функцией MPI_Comm_rank через переменную rank, лежит в диапазоне от 0 до size-1.

double MPI_Wtime(void)

Эта функция возвращает астрономическое время в секундах (вещественное число), прошедшее с некоторого момента в прошлом. Если некоторый участок программы окружить вызовами данной функции, то разность возвращаемых значений покажет время работы данного участка. Гарантируется, что момент времени, используемый в качестве точки отсчета, не будет изменен за время существования процесса. Заметим, что эта функция возвращает результат своей работы не через параметры, а явным образом.

Простейший пример программы, в которой использованы описанные выше функции, выглядит так:

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("Process %d size %d \n", me, size);

MPI_Finalize();

}

Строка, соответствующая функции printf, будет выведена столько раз, сколько процессов было порождено при вызове MPIInit. Порядок появления строк за­ранее не определен и может быть, вообще говоря, любым. Гарантируется толь­ко то, что содержимое отдельных строк не будет перемешано друг с другом.

Наши рекомендации