Любая MPI-программа должна начинаться с вызова функции инициализации MPI - функции MPI_Init. В результате выполнения этой функции создается область связи, описы┐ваемая предопределенным коммуникатором MPI_COMM_WORLD, в которую помещаются все запущенные процессы. Процессы упорядочены и пронумерованы от 0 до nproc-1, где nproc равно числу запущенных процессов. Кроме этого, создается предопределенный коммуникатор MPI_COMM_SELF, описывающий свою область связи для каждого отдельного процесса.
Вызов функции инициализации MPI_Init отличается в языках Cи и Fortran:
C:
int MPI_Init(int *argc, char ***argv)
Fortran:
MPI_INIT(IERROR)
INTEGER IERROR
В программах на Cи каждому процессу при инициализации передаются аргументы функции main, полученные из командной строки. В программах на языке Фортран параметр IERROR является выходным и возвращает код ошибки.
Функция завершения MPI-программы MPI_Finalize
C:
int MPI_Finalize(void)
Fortran:
MPI_FINALIZE(IERROR)
INTEGER IERROR
Функция закрывает все MPI-процессы и ликвидирует все области связи.
Функция определения числа процессов в области связи MPI_Comm_size
C:
int MPI_Comm_size(MPI_Comm comm, int *size)
Fortran:
MPI_COMM_SIZE(COMM, SIZE, IERROR)
INTEGER COMM, SIZE, IERROR
IN comm - коммуникатор;
OUT rank - номер процесса, вызвавшего функцию.
Функция возвращает номер процесса, вызвавшего эту функцию. Номера процессов лежат в диапазоне 0..size-1 (значение size может быть определено с помощью предыдущей функции). Подпрограмма является локальной.
В минимальный набор следует включить также две базовых коммуникационных функции.
Функция передачи сообщения MPI_Send
C:
int MPI_Send(void* buf, int count, MPI_Datatype datatype,int dest,int tag,MPI_Comm comm)
Fortran:
MPI_SEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM,IERROR)
<type> BUF(*)
INTEGER COUNT, DATATYPE, DEST, TAG, COMM, IERROR
IN buf - адрес начала расположения пересылаемых данных;
IN count - число пересылаемых элементов;
IN datatype - тип посылаемых элементов;
IN dest - номер процесса-получателя в группе, связанной скоммуникатором comm;
IN tag - идентификатор сообщения;
IN comm - коммуникатор области связи.
Функция выполняет посылку count элементов типа datatype сообщения с идентификатором tag процессу dest в области связи коммуникатора comm. Переменная buf - это, как правило, массив или скалярная переменная. В последнем случае значение count = 1.
Функция приема сообщения MPI_Recv
C:
int MPI_Recv(void* buf, int count, MPI_Datatype datatype, int source, int tag,MPI_Comm comm, MPI_Status *status)
Fortran:
MPI_RECV(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM,STATUS, IERROR)
<type> BUF(*)
INTEGER COUNT, DATATYPE, SOURCE, TAG, COMM,STATUS(MPI_STATUS_SIZE), IERROR
OUT buf - адрес начала расположения принимаемого сообщения;
IN count - максимальное число принимаемых элементов;
IN datatype - тип элементов принимаемого сообщения;
IN source - номер процесса-отправителя;
IN tag - идентификатор сообщения;
IN comm - коммуникатор области связи;
OUT status - атрибуты принятого сообщения.
Функция выполняет прием count элементов типа datatype сообщения с идентификатором tag от процесса source в области связи коммуникатора comm.
Более детально операции обмена сообщениями будут рассмотрены в следующем разделе, а в заключение этого раздела рассмотрим функции, которые не входят в очерченный минимальный набор, но которые важны для разработки эффективных параллельных программ. Речь идет о функциях отсчета времени. С одной стороны, такие функции имеются в составе всех операционных систем, а с другой стороны, не существует единых стандартов в их реализации. Поэтому разработчики MPI, добиваясь полной независимости приложений от операционной среды, определили свои функции отсчета времени.
Функция отсчета времени (таймер) MPI_Wtime
C:
double MPI_Wtime(void)
Fortran:
DOUBLE PRECISION MPI_WTIME().
Функция возвращает астрономическое время в секундах, прошедшее с некоторого момента в прошлом (точки отсчета). Гарантируется, что эта точка отсчета не будет изменена в течение жизни процесса. Для хронометража участка программы вызов функции делается в начале и конце участка и определяется разница между показаниями таймера. Приведем пример фрагмента программы использующего эту функцию.
{
double starttime, endtime;
starttime = MPI_Wtime();
: хронометрируемый участок :
endtime = MPI_Wtime();
printf("Выполнение заняло %f секунд\n",endtime-starttime);
}
Функция MPI_Wtick, имеющая точно такой же синтаксис, возвращает разрешение таймера (минимальное значение кванта времени).
Приведем примеры простейших MPI-программ
Программа simple.c
#include "mpi.h" #include <stdio.h> int main(argc,argv) int argc; char *argv[]; { int numtasks, rank, rc; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&numtasks); MPI_Comm_rank(MPI_COMM_WORLD,&rank); printf ("Number of tasks= %d My rank= %d\n", numtasks,rank); MPI_Finalize(); }
Программа simple.f
program simple include 'mpif.h' integer numtasks, rank, ierr, rc call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) print *, 'Number of tasks=',numtasks,' My rank=',rank call MPI_FINALIZE(ierr) end