MPI_Recv (address, maxcount, datatype, source, tag, comm, status)

Лабораторная работа №1

ПАРАЛЛЕЛЬНОЕ ПРОГРАММИРОВАНИЕ В MPI.

ОСНОВНЫЕ КОММУНИКАЦИОННЫЕ ОПЕРАЦИИ

Цель работы: знакомство со стандартом MPI и изучение коммуникационных операций парного и коллективного обмена.

Лабораторный комплекс. В состав лабораторного комплекса входят аппаратные средства: ПЭВМ IBM PC, локальная сеть, а также программные средства: Windows 2000/ХР, Visual C++, MPICH for NT.

Программа работы

1) изучить возможности использования и параметры функций MPI;

2) написать программу для решения задачи согласно выбранному варианту.

Основные теоретические сведения

1. Краткая характеристика MPI

Система программирования MPIимеет следующие особенности:

• MPI − это библиотека. Она определяет имена, вызовы процедур и результаты их работы. Программы, которые пишутся на FORTRAN, C, и C++ компилируются обычными компиляторами и связаны с MPI-библиотекой.

• MPI − описание, а не реализация. Все поставщики параллельных компьютерных систем предлагают реализации MPI для своих машин как бесплатные, и они могут быть получены из Интернет. Правильная MPI-программа должна выполняться на всех реализациях без изменения.

• MPI соответствует модели многопроцессорной ЭВМ с передачей сообщений.

Процесс MPI- этопрограммная единица, у которой имеется собствен­ное адресное пространство и одна или несколько нитей. Процессор− фрагмент аппаратных средств, способный к выполнению программы. Некоторые реализации MPI устанавливают, что в программе MPI всегда одному процессу соответствует один процессор; другие − позволяют размещать много процессов на каждом процессоре.

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

Процессы в MPI принадлежат группам. Если группа содержит n процессов, то процессы нумеруются внутри группы номерами, кото­рые являются целыми числами от 0 до n-l. Имеется начальная группа, которой принадлежат все процессы в реализации MPI.

Понятия контекста и группы объединены в едином объекте, назы­ваемом коммуникатором. Таким образом, отправитель или получа­тель, определенные в операции посылки или получения, всегда обращается к номеру процесса в группе, идентифицированной данным коммуникатором.

Если в кластере используются SMP-узлы (симметричная много­процессорная система с множественными процессорами), то для орга­низации вычислений возможны два варианта.

1. Для каждого процессора в SMP-узле порождается отдельный MPI-процесс. MPI-процессы внутри этого узла обмениваются сообщениями через разделяемую память (необходимо настроить MPICH соответствующим образом).

2. На каждой узле запускается только один MPI-процесс. Внутри каждого MPI-процесса производится распараллеливание в модели "общей памяти", например с помощью директив OpenMP.

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

MPI_Init Инициализация MPI
MPI_Comm_size Определение числа процессов
MPI_Comm_rank Определение процессом собственного номера
MPI_Send Посылка сообщения
MPI_Recv Получение сообщения
MPI_Finalize Завершение программы MPI

В МPI базисной операцией посылки является операция:

MPI_Send (address, count, datatype, destination, tag, comm),

где (address, count, datatype)− количество (count)объектов типа datatype,начинающихся с адреса addressв буфере посылки; destination - номер получателя в группе, определяемой коммуника­тором comm; tag− целое число, используемое для описания сообще­ния; comm- идентификатор группы процессов и коммуникационный контекст.

Базисной операцией приема является операция:

MPI_Recv (address, maxcount, datatype, source, tag, comm, status),

где (address, count, datatype) описывают буфер приемника, как в случае MPI_Send; sourse- номер процесса-отправителя сообщения в группе, определяемой коммуникатором comm; status- содержит ин­формацию относительно фактического размера сообщения, источника и тэга. Sourse, tag, countфактически полученного сообщения восста­навливаются на основе status.

Передача и прием сообщений процессами - это базовый коммуни­кационный механизм MPI. Основными операциями парного обмена являются операции send(послать) и receive(получить). Их исполь­зование иллюстрируется следующим примером:

#include "mpi.h"

main( argc, argv) {

int argc;

char **argv;

{ char message[20];

int myrank;

MPI_Status status;

MPI_Init( &argc, &argv);

MPI_Comm_rank( MPI_COMM_WORLD, &myrank);

if (myrank == 0) /* код для процесса 0 */

{ strcpy (message, "Hello, there");

MPI_Send(message,strlen(message),MPI_CHAR, 1,99, MPI_COMM_WORLD);

}

else /* код для процесса 1 */

{ MPI_Recv(message, 20, MPI_CHAR, 0, 99, MPI_COMM_WORLD, &status);

printf("received :%s:\n", message);

} MPI_Finalize();

}

В этом примере процесс с номером 0 (myrank= 0)посылает со­общение процессу с номером 1, используя операцию посылки MPI_Send.Эта операция описывает буфер посылающего процесса, из которого извлекаются посылаемые данные. В приведенном примере посылающий буфер состоит из накопителя в памяти процесса 0, содержащего переменную message.Размещение, размер и тип буфера посылающего процесса описываются первыми тремя параметрами операции send.Посланное сообщение будет содержать 13 символов этой переменной. Операция посылки также связывает с сообщением его атрибуты. Атрибуты определяют номер процесса-получателя сообщения и содержат различную информацию, которая может быть использована операцией receive,чтобы выбрать определенное сооб­щение среди других. Последние три параметра операции посылки описывают атрибуты посланного сообщения. Процесс 1 (myrank= 1)получает это сообщение, используя операцию приема MPI_Recv,и данные сообщения записываются в буфер процесса-получателя. В приведенном примере буфер получателя состоит из накопителя в па­мяти процесса один, содержащего строку message.Первые три параметра операции приема описывают размещение, размер и тип буфера приема. Следующие три параметра необходимы для выбора входного сообщения. Последний параметр необходим для возврата информации о только что полученном сообщении.

Ранее говорилось, что для написания большинства программ достаточно 6 функции, среди которых основными являются функции обмена сообщениями типа "точка-точка" (в дальнейшем - функции парного обмена). Программу вычисления можно написать с помощью функций парного обмена, но функции, относящиеся к классу коллективных обменов, как правило, будут эффективнее. В MPI используются коллективные операции, которые можно разделить на два вида:

• операции перемещения данных между процессами. Самый простой из них - широковещание (broadcasting), MPI имеет много и более сложных коллективных операций передачи и сбора сообщений;

• операции коллективного вычисления (минимум, максимум, сумма и другие, в том числе и определяемые пользователем операции).

В обоих случаях библиотеки функций коллективных операций строятся с использованием знания о преимуществах структуры машины, чтобы увеличить параллелизм выполнения этих операций.

В качестве примера параллельной программы, написанной в стандарте MPI для языка С, рассмотрим программу вычисления числа π. Число π можно определить следующим образом:

MPI_Recv (address, maxcount, datatype, source, tag, comm, status) - student2.ru

Вычисление интеграла затем заменяют вычислением суммы

MPI_Recv (address, maxcount, datatype, source, tag, comm, status) - student2.ru

MPI_Recv (address, maxcount, datatype, source, tag, comm, status) - student2.ru

#include "mpi.h"

#include <math.h>

int main (int argc, char *argv[ ])

{ int n, myid, numprocs, i;

double mypi, pi, h, sum, x, t1, t2, PI25DT = 3.141592653589793238462643;

MPI_Init(&argc, &argv);

MPI_Comm_size(MPI_COMM_WORLD, &numprocs);

MPI_Comm_rank(MPI_COMM_WORLD,&myid);

while (1)

{

if (myid == 0) { printf ("Enter the number of intervals: (0 quits)");

scanf("%d",&n);

t1 = MPI_Wtime();

}

MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);

if(n == 0) break;

else

{ h =1.0/(double) n;

sum = 0.0;

for (i = myid +1; i <= n; i+= numprocs)

{ x = h * ((double)i - 0.5); sum+=(4.0/(1.0 + x*x));

}

mypi = h * sum;

MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0,

MPI_COMM_WORLD); if (myid == 0) { t2 = MPI_Wtime();

printf ("pi is approximately %.16f. Error is %.16f\n",pi, fabs(pi - PI25DT)); printf ("'time is %f seconds \n", t2-t1);

} } }

MPI_Finalize(); return 0; }

В программе после нескольких строк определения переменных следуют три строки, которые есть в каждой MPI-программе:

MPI_Init(&argc, &argv);

MPI_Comm_size(MPI_COMM_WORLD, &numprocs);

MPI_Comm_rank(MPI_COMM_WORLD,&myid);

Обращение к MPI_Initдолжно быть первым обращением в MPI-программе, оно устанавливает "среду" MPI. В каждом выполнении про­граммы может выполняться только один вызов MPI_Init.

Коммуникатор MPI_COMM_WORLDописывает состав процес­сов и связи между ними. Вызов MPI_Comm_sizeвозвращает в numprocsчисло процессов, которые пользователь запустил в этой программе. Значение numprocs− размер группы процессов, связан­ной с коммуникатором MPI_COMM_WORLD.Процессы в любой группе нумеруются последовательными целыми числами, начиная с 0. Вызывая MPI_ Comm_rank,каждый процесс выясняет свой номер (rank)в группе, связанной с коммуникатором. Затем главный процесс (который имеет myid=0)получает от пользователя значение числа прямоугольников n:

MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);

Первые три параметра соответственно обозначают адрес, количе­ство и тип данных. Четвертый параметр указывает номер источника данных (головной процесс), пятый параметр - название коммуникато­ра группы. Таким образом, после обращения к MPI_Bcastвсе процес­сы имеют значение n и собственные идентификаторы, что является достаточным для каждого процесса, чтобы вычислить mypi− свой вклад в вычисление π. Для этого каждый процесс вычисляет область каждого прямоугольника, начинающегося с myid+l.

Затем все значения mypi,вычисленные индивидуальными процес­сами, суммируются с помощью вызова Reduce:

MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

Первые два параметра описывают источник и адрес результата. Третий и четвертый параметр описывают число данных и их тип, пятый параметр - тип арифметико-логической операции, шестой – номер процесса для размещения результата.

Затем по метке 10 управление передается на начало цикла. Этим пользователю предоставляется возможность задать новое n и повысить точность вычислений. Когда пользователь печатает нуль в ответ на запрос о новом n, цикл завершается, и все процессы выполняют:

MPI_Finalize();

после которого любые операции MPI выполняться не будут.

Функция MPI_Wtime() используется для измерения времени ис­полнения участка программы, расположенного между двумя включе­ниями в программу этой функции.

Коллективные функции Bcast и Reduce можно выразить через парные операции Send и Recv. Например, для той же программы вычисления числа π операция Bcast для рассылки числа интервалов выражается через цикл следующим образом:

for (i=0; i<numprocs; i++)

MPI_Send(&n, 1, MPI_INT, i, 0, MPI_COMM_WORLD);

Параллельная MPI программа может содержать различные испол­няемые файлы. Этот стиль параллельного программирования часто называется MPMD (множество программ при множестве данных) в отличие от программ SPMD (одна программа при множестве данных). SPMD не следует путать с SIMD. Вышеприведенная программа вычисления числа π относится к классу программ SPMD. Такие программы значительно легче писать и отлаживать, чем программы MPMD. В общем случае системы SPM и MPI могут имитировать друг друга:

1. Посредством организации единого адресного пространства для физически разделенной по разным процессорам памяти.

2. На SMP-машинах вырожденным каналом связи для передачи сообщений служит разделяемая память.

3. Путем использования компьютеров с разделяемой виртуальной памятью. Общая память как таковая отсутствует. Каждый процессор имеет собственную локальную память и может обращаться к локальной памяти других процессоров, используя "глобальный адрес". Если "глобальный адрес" указывает не на локальную память, то доступ к памяти реализуется с помощью сообщений, пересылаемых по коммуникационной сети.

Операции блокирующей передачи и блокирующего приема.

Блокирующая передача:

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