Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

u_course

.pdf
Скачиваний:
39
Добавлен:
04.06.2015
Размер:
1.87 Mб
Скачать

Средства разработки параллельных программм

181

вторному использованию по возвращении из функции. Передача по готовности (MPI_Rsend()) похожа на синхронную передачу, но проверка готовности получателя принимать данные не выполняется, то есть, если в момент инициализации передачи получатель не готов, то происходит ошибка. Передача по готовности в некотором смысле реализует рандеву, то есть передача состоится только в том случае, если получатель ее ожидает. И, наконец, автоматический режим передачи (MPI_Send()) предполагает, что система сама делает выбор в пользу синхронной или буферизованной передачи на основании размера передаваемых данных.

Блокирующая функция приема существует одна для всех режимов (MPI_Recv()), и возврат из нее означает, что данные приняты.

Обобщенные сведения об основных функциях двухточечного обмена содержатся в таблице 6.1.

Важным моментом, связанным с автоматическим режимом, является то, что критический размер массива не определяется стандартом и может изменяться в зависимости от реализации. С этим может быть связано такое явление, как прекращение работы программы с ростом ее размера, когда синхронный режим неожиданно для пользователя сменяется буферизованным, а памяти в системе не хватает. Поэтому при передаче крупных блоков данных лучше управлять буферизацией явно (MPI_Bsend()/MPI_Ibsend()), а при передаче действительно крупных – не использовать буферизацию (то есть пользовать-

ся MPI_Ssend()/MPI_Issend()) .

Существует также функция совмещенного приема и передачи MPI_Sendrecv(), которую рекомендуется по возможности применять.

Перед началом приема можно узнать о наличие сообщения и его параметрах блокирующей функцией MPI_Probe() или ее неблокирующим вариантом MPI_Iprobe(). Эти функции возвращают в структуру специального типа MPI_Status сведения об отправителе, теге и длине сообщения.

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

Чего совершенно точно не стоит делать – это пересылать данные малыми порциями. Какова бы ни была коммуникационная сеть, производительность множества мелких передач всегда будет намного ниже, чем одной крупной.

Средства разработки параллельных программм

182

Стандартный режим передачи

Синхронный режим передачи

Таблица 6.1

Основные функции двухточечных обменов

Блокирующая форма

MPI_Send(…);

Локальная операция.

Начинается не зависимо от того, был ли зарегистрирован соответствующий прием.

Завершается после освобождения системного буфера: сообщение «ушло в сеть», но может еще некоторое время «гулять по сети».

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

MPI_Ssend(…);

Не локальная операция. Начинается не зависимо от того, был ли зарегистрирован соответствующий прием.

Завершается при получении уведомления о начале приема процес- сом-получателем.

Дополнительные сведения: сооб-

щение не буферизуется на стороне отправителя, по окончании операции буфер может использоваться дальше. Передача хотя и медленная, но не позволяет сети переполняться «гуляющими» сообщениями

Неблокирующая форма

MPI_Isend(…);

Локальная операция.

Инициализация передачи означает формирование запроса на выполнение операции обмена и связывание его со специальным идентификатором операции (выходной параметр).

Успешность проверки гарантиру-

ет, что сообщение ушло в сеть.

MPI_Issend(…);

Локальная операция.

Инициализация передачи означает формирование запроса на выполнение операции обмена и связывание его со специальным идентификатором операции (выходной параметр).

Успешность проверки гарантиру-

ет, что начат прием сообщения.

Средства разработки параллельных программм

Синхронный режим передачи

Передача по готовности

 

 

 

 

183

MPI_Bsend(…);

 

 

MPI_Ibsend(…);

 

 

Локальная операция.

 

 

 

 

Локальная операция.

Перед использованием

необходи-

мо выделить буфер с помощью

Инициализация передачи означает

функции

 

 

 

формирование запроса на выпол-

 

 

 

 

MPI_Buffer_attach(…);

 

нение операции обмена и связы-

Передача начинается не зависимо

вание его со специальным иден-

от того, был ли зарегистрирован

тификатором операции (выход-

соответствующий прием.

 

ной параметр).

Завершается сразу, поскольку со-

Успешность проверки гарантиру-

общение копируется в выделенный

ет, что отправляемые данные уш-

буфер, в котором ожидает опера-

ли в сеть или скопированы в вы-

ции обмена.

 

 

деленный буфер. После этого пе-

Дополнительные сведения: при за-

редачу нельзя отменить. Если не

вершении

операции

необходимо

будет зарегистрирован соответст-

освободить

буфер

с

помощью

вующий прием, то буфер уже

функции

 

 

 

нельзя будет освободить.

MPI_Buffer_detach(…);

 

 

Для работы с буфером также сле-

которая дожидается

завершения

дует использовать функции

выполнения обмена

и

обнуляет

MPI_Buffer_attach(…);

буфер.

 

 

 

MPI_Buffer_detach(…);

MPI_Rsend(…);

 

 

 

Не локальная операция.

 

MPI_Irecv(…);

Передача выполняется только ес-

Локальная операция.

ли инициирован соответствующий

Инициализация передачи означает

прием.

 

 

 

Если прием не зарегистрирован,

разрешение начать прием, кото-

результат выполнения операции не

рый происходит в фоновом ре-

определен. Сообщение просто вы-

жиме. Если принимающей сторо-

брасывается в сеть без буфериза-

ной прием к моменту вызова

ции.

 

 

 

функции не инициализирован, то

Завершается сразу, не гарантирует

результат выполнения операции

получение сообщения.

 

не определен.

Дополнительные сведения: самый

Успешность проверки гарантиру-

быстрый (не используются этапы

установки

межпроцессорных свя-

ет наличие сообщения в буфере

зей), но и самый опасный режим

приема принимающего процесса.

передачи, при отладке рекоменду-

 

ется заменять стандартным.

 

 

 

 

 

 

Средства разработки параллельных программм

 

MPI_Recv(…);

 

 

 

Локальная операция.

 

 

 

Если длина

сообщения

меньше

 

буфера приема, то изменяется

 

только часть буфера.

 

 

 

Если длина сообщения больше бу-

 

фера приема, то прием блокирует-

сообщения

ся.

 

 

 

MPI_Get_count(…);

 

 

 

Информацию о длине получаемого

 

сообщения можно узнать с помо-

Прием

щью функции

 

 

Дополнительные сведения: для по-

 

 

лучение сообщения от произволь-

 

ного источника определена специ-

 

альная константа MPI_ANY_SOURSE.

 

Для получение сообщения с про-

 

извольным тегом определена спе-

 

циальная константа MPI_ANY_TAG.

 

Окончание

приема

гарантирует

 

наличие сообщения

в

буфере

 

приема.

 

 

 

 

 

 

 

 

184

MPI_Irecv(…);

Локальная операция.

Инициализация передачи означает разрешение начать прием, который происходит в фоновом режиме.

Успешность проверки гарантиру-

ет наличие сообщения в буфере приема и освобождение системного буфера.

Следовать ли стандарту в той части, которая запрещает доступ даже на чтение в буфер передачи при использовании неблокирующей небуферизующей передачи? Авторам неизвестны примеры вычислительных систем, на которых это требование имеет практический смысл; с другой стороны, это не значит, что их нет или не появится в обозримом будущем. Видимо, в программах, написанных с расчетом на длительное использование, следует на уровне архитектуры предусмотреть возможность соблюдения этого требования.

Групповые функции необходимы для того, чтобы собрать с одного множества процессов некоторые данные, выполнить над ними какую-то операцию (предопределенную, определенную пользователем или не выполнять никакой) и разместить результат в другое множество процессов. Множества процессов могут пересекаться или нет, состоять из одного или более процессов. Однако их объединение обязательно должно включать в себя все процессы некоторой группы и прежде, чем на всех процессах группы не будет вызвана одна и та же групповая функция (конечно, с разными параметрами),

Средства разработки параллельных программм

185

ни из одного вызова соответствующей функции управление не вернется. В этом смысле все групповые функции – синхронные и блокирующие.

Следует понимать, что смешивать парные и групповые функции нельзя, в том смысле, что сообщение, посланное групповой функцией, не получится принять с помощью MPI_Recv, и наоборот.

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

MPI_Allreduce(&res0, &res, 1, mpi_real, MPI_SUM, C_Group);

Этот вызов должен быть выполнен всеми процессами группы C_Group. Вообще групповые функции можно разделить на следующее множест-

во.

Синхронизация барьером

Глобальные функции связи, включающие

1)передачу данных (broadcast) от одного процесса группы ко всем процессам группы;

2)сбор данных (gather) от всех процессов группы к одному процессу этой группы;

3)рассылку данных (scatter) от одного процесса группы ко всем процессам группы;

4)сбор данных в цикле по всем процессам группы (allgather), т.е. все элементы группы получают результат от всех;

5)рассылку /сбор (scatter/gather) данных от всех элементов ко всем элементам группы (полный обмен, alltoall).

На рис. 6.1 проиллюстрированы результаты выполнения глобальных функций связи для шести процессов. В каждой клетке представлены локальные данные в одном процессе. Например, при выполнении операции broadcast данные A0 передает только первый процесс, а другие процессы принимают эти данные.

Глобальные операции приведения (редуцирования), такие как, sum, max, min или определенные пользователем функции, включающие:

1)редуцирование, при котором результат возвращается всем процессам группы (reduce);

2)редуцирование, при котором результат возвращается только одному процессу группы (allreduce);

3)объединенние редуцирования и операции рассылки (reduce–

scatter);

Средства разработки параллельных программм

186

4) развертку по всем элементам группы (scan).

На рис. 6.2 проиллюстрированы результаты выполнения функций приведения для группы из трех процессов на примере операции суммирования.

Рис. 6.1. Глобальные функции связи для группы из шести процессов

Средства разработки параллельных программм

187

Рис. 6.2. Глобальные операции приведения для группы из трех процессов

Латентность и пропускная способность

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

Пропускная способность – это величина, обратная времени, необходимого для передачи одного байта. Пропускная способность обычно выражается в Мб/с. Пропускная способность важна, когда передаются сообщения больших размеров.

Для улучшения характеристик латентности и пропускной способности необходимо учитывать следующие соображения:

лучше использовать архивацию данных для больших сообщений, а также использовать описываемые типы данных вместо MPI_PACK() и MPI_UNPACK() там, где это возможно;

для устранения вызовов MPI_Send() и MPI_Recv() каждый раз при коммуникации процессов, по возможности следует использовать коллективные операции;

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

Средства разработки параллельных программм

188

предпочтительнее использовать MPI_RECV_INIT() и MPI_STARTALL() вместо вызова MPI_Irecv() в цикле в случаях, когда запросы на прием сообщений не могут быть выполнены сразу.

Заключительные замечания

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

КОНТРОЛЬНЫЕВОПРОСЫ

1.Специфика программирования для параллельных вычислительных систем с распределенной памятью.

2.Механизм передачи сообщений. Синхронная и асинхронная передача сообщений.

3.Чем механизм передачи сообщений отличается от передачи данных через общую память?

4.Какие методы взаимодействия параллельных процессов используются при передаче сообщений?

5.Какие методы планирования процессов целесообразно применять для вычислительных систем с распределенной памятью?

6.Общая концепция построения MPI-программы.

7.Понятие ускорения и эффективности параллельной программы.

8.Организация вычислений в MPI: понятие группы процессов, понятие топологии.

9.Организация вычислений в MPI: пользовательские типы данных.

10.Парные обмены в MPI. Блокирующие и неблокирующие функции передачи данных.

11.Четыре режима посылки данных в MPI.

12.Функции приема данных в MPI.

13.Групповые функции в MPI.

14.Проблема латеннтности и пропускной способности.

ГЛАВА7. ОСНОВНЫЕФУНКЦИИСТАНДАРТА

MPI

В настоящей главе описаны сведения об основных функциональных возможностях MPI. Многие функции стандарта не представлены здесь, для более детального знакомства следует обратиться к описанию стандарта MPI или, например, монографиям [2,4].

Для любой функции MPI можно указать три основных признака.

Блокирующие функции останавливают (блокируют) выполнение процесса до завершения требуемой операции. Неблокирующие функции возвращают управление немедленно, выполнение операции продолжается в фоновом режиме. Таким образом, неблокирующая функция – это заявка на выполнение операции, что бы проследить за удовлетворением системой заявки одним из выходных параметров функции является requests. Существуют специальные функции проверки окончания операции, в которых requests является входным параметром. До окончания операции система запрещает использовать переменные и массивы, которые являлись аргументами неблокирующей функции.

Локальные функции не инициируют пересылок данных между ветвями. Например, поскольку копии системных данных хранятся в каждой ветви программы, то большинство информационных функций является локальными, т.к. копии системных данных уже хранятся в каждой ветви. Естественно функция передачи MPI_Send() локальной не является, но функция приема MPI_Recv() – локальная поскольку пассивно ждет поступления данных, ничего не пытаясь сообщить другим ветвям.

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

Например, функция MPI_Barrier(...) является блокирующей, нелокальной коллективной, а функция MPI_Isend(...) неблокирующей, нелокальной и не коллективной.

В языке С все функции имеют целый тип и в случае успешного завершения возвращают MPI_SUCCESS, в противном случае – код ошибки.

ПОНЯТИЕГРУППЫ, ОБЛАСТИСВЯЗИ, КОММУНИКАТОРА

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

Средства разработки параллельных программм

190

жение программиста предоставлен тип MPI_Group и набор функций, работающих с переменными и константами этого типа.

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

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

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

Программе пользователя в распоряжение предоставляется коммуникатор – описатель области связи, для которого предусмотрен специальный тип MPI_Comm, описывающий некоторую распределенную структуру данных. Области связи автоматически создаются и уничтожаются вместе с коммуникаторами. Нет отдельной функции – «создать область связи». Так для стартовой области связи автоматически создается коммуникатор с идентификатором

MPI_COMM_WORLD.

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

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

Самым общим способом создания коммуникатора является связывание его с группой процессов. При этом следует придерживаться следующей технологии (подробное описание функций следует смотреть в стандарте):

функцией MPI_Comm_group(comm, &group) определяется группа group,

связанная с существующим коммуникатором comm;

на базе существующих групп функциями семейства MPI_Group_*() создаются новые группы с нужным набором ветвей (в MPI определено семь функций конструирования групп, а так же несколько информационных функций);

для итоговой группы процессов group_end коммуникатора comm

функцией MPI_Comm_create(comm, group_end, comm_new) создается коммуникатор

comm_new;

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]