Книжная полка Сохранить
Размер шрифта:
А
А
А
|  Шрифт:
Arial
Times
|  Интервал:
Стандартный
Средний
Большой
|  Цвет сайта:
Ц
Ц
Ц
Ц
Ц

Параллельное программирование с использованием технологии MPI

Покупка
Новинка
Артикул: 833557.01.99
Доступ онлайн
1 000 ₽
В корзину
Технология MPI является основным средством программирования для кластерных систем и компьютеров с распределенной памятью, но может применяться также и на вычислительных системах других типов. Курс включает в себя описание большинства основных процедур стандарта MPI-1.1 с примерами их применения и практические сведения, которые могут потребоваться при написании реальных программ. Основное описание ведется с использованием вызовов процедур MPI из программ на языке Фортран, однако указаны также основные отличия в использовании вызовов аналогичных функций из программ на языке Си.
Антонов, А. С. Параллельное программирование с использованием технологии MPI : краткий курс / А. С. Антонов. - Москва : ИНТУИТ, 2016. - 63 с. - Текст : электронный. - URL: https://znanium.ru/catalog/product/2155105 (дата обращения: 05.05.2024). – Режим доступа: по подписке.
Фрагмент текстового слоя документа размещен для индексирующих роботов. Для полноценной работы с документом, пожалуйста, перейдите в ридер.
Параллельное программирование с использованием
технологии MPI

2-е издание, исправленное

Антонов А.С.

Национальный Открытый Университет “ИНТУИТ”
2016

2
Параллельное программирование с использованием технологии MPI/ А.С. Антонов - М.:
Национальный Открытый Университет “ИНТУИТ”, 2016

Технология MPI является основным средством программирования для кластерных систем и
компьютеров с распределенной памятью, но может применяться также и на вычислительных
системах других типов.
Курс включает в себя описание большинства основных процедур стандарта MPI-1.1 с примерами их
применения и практические сведения, которые могут потребоваться при написании реальных
программ. Основное описание ведется с использованием вызовов процедур MPI из программ на
языке Фортран, однако указаны также основные отличия в использовании вызовов аналогичных
функций из программ на языке Си.

(c) ООО “ИНТУИТ.РУ”, 2008-2016
(c) Антонов А.С., 2008-2016

3
Основные понятия

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

Наиболее распространенной технологией программирования для параллельных
компьютеров с распределенной памятью в настоящее время является MPI. Основным
способом взаимодействия параллельных процессов в таких системах является передача
сообщений друг другу. Это и отражено в названии данной технологии - Message
Passing Interface (интерфейс передачи сообщений). Стандарт MPI фиксирует
интерфейс, который должен соблюдаться как системой программирования на каждой
вычислительной платформе, так и пользователем при создании своих программ.
Современные реализации, чаще всего, соответствуют стандарту MPI версии 1.1. В
1997- 1998 годах появился стандарт MPI-2.0, значительно расширивший
функциональность предыдущей версии. Однако до сих пор этот вариант MPI не
получил широкого распространения и в полном объеме не реализован ни на одной
системе. Везде далее, если иного не оговорено, мы будем иметь дело со стандартом
MPI-1.1.

MPI поддерживает работу с языками Фортран и Си. В данном пособии примеры и
описания всех процедур будут даны с использованием языка Фортран. Однако это
совершенно не является принципиальным, поскольку основные идеи MPI и правила
оформления отдельных конструкций для этих языков во многом схожи. Полная версия
интерфейса содержит описание более 125 процедур и функций. Наша задача -
объяснить идею технологии и помочь освоить необходимые на практике компоненты.
Дополнительную информацию об интерфейсе MPI можно найти на тематической
странице Информационно-аналитического центра по параллельным вычислениям в
сети Интернет ссылка: http://parallel.ru/tech/tech_dev/mpi.html.

Интерфейс MPI поддерживает создание параллельных программ в стиле MIMD

(Multiple Instruction Multiple Data), что подразумевает объединение процессов с
различными исходными текстами. Однако писать и отлаживать такие программы очень
сложно, поэтому на практике программисты гораздо чаще используют SPMD-моделъ
(Single Program Multiple Data) параллельного программирования, в рамках которой для
всех параллельных процессов используется один и тот же код. В настоящее время все
больше и больше реализаций MPI поддерживают работу с нитями.

Поскольку MPI является библиотекой, то при компиляции программы необходимо
прилинковать соответствующие библиотечные модули. Это можно сделать в
командной строке или воспользоваться предусмотренными в большинстве систем
командами или скриптами mpicc++ (для программ на языке Си), mpicc++ (для программ
на языке Си++), и mpif 77/ mpif 90 (для программ на языках Фортран 77/90). Опция
компилятора "-о name" позволяет задать имя name для получаемого
выполнимого файла, по умолчанию выполнимый файл yказывается на out, например:

mpif77 -o program program.f .

4
После получения выполнимого файла необходимо запустить его на требуемом
количестве процессоров. Для этого обычно предоставляется команда запуска MPI-
приложений mpirun, например:

mpirun -np N <программа с аргументами>,

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

Все дополнительные объекты: имена процедур, константы, предопределенные типы
данных и т.п., используемые в MPI, имеют префикс MPI_. Если пользователь не будет
использовать в программе имен с таким префиксом, то конфликтов с объектами MPI
заведомо не будет. В языке Си, кроме того, является существенным регистр символов в
названиях функций. Обычно в названиях функций MPI первая буква после префикса
MPI_ пишется в верхнем регистре, последующие буквы - в нижнем регистре, а
названия констант MPI записываются целиком в верхнем регистре. Все описания
интерфейса MPI собраны в файле mpif.h (mpi.h) , поэтому в начале MPI-программы
должна стоять директива include ‘mpif.h’ ( #include “mpi.h” для программ на языке
Си).

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

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

При старте программы всегда считается, что все порожденные процессы работают в
рамках всеобъемлющего коммуникатора, имеющего предопределенное имя

MPI_COMM_WORLD. Этот коммуникатор существует всегда и служит для взаимодействия
всех запущенных процессов MPI-программы. Кроме него при старте программы
имеется коммуникатор MPI_COMM_SELF, содержащий только один текущий процесс, а
также коммуникатор MPI_COMM_NULL, не содержащий ни одного процесса. Все
взаимодействия процессов протекают в рамках определенного коммуникатора,
сообщения, переданные в разных коммуникаторах, никак не мешают друг другу.

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

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

В последнем аргументе (в языке Си - в возвращаемом значении функции) большинство
процедур MPI возвращают информацию об успешности завершения. В случае
успешного выполнения возвращается значение MPI_SUCCESS, иначе - код ошибки. Вид
ошибки, которая произошла при выполнении процедуры, можно будет определить из
ее описания. Предопределенные значения, соответствующие различным ошибочным
ситуациям, перечислены в файле mpif .h..

6
Общие процедуры MPI

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

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

MPI_INIT(IERR) INTEGER IERR

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

MPI_Init передаются указатели на аргументы командной строки программы argc и

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

MPI_FINALIZE(IERR) INTEGER IERR

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

Пример простейшей MPI-программы на языке Фортран выглядит следующим образом:

program example1
include 'mpif.h'
integer ierr
print *, 'Before MPI_INIT'
call MPI_INIT(ierr)
print *, 'Parallel section'
call MPI_FINALIZE(ierr)
print *, 'After MPI_FINALIZE'
end

В зависимости от реализации MPI строчки ‘Before MPI_INIT’ И ‘After MPI_FINALIZE’
может печатать либо один выделенный процесс, либо все запущенные процессы
приложения. Строчку ‘Parallel section’ должны напечатать все процессы. Порядок
вывода строк с разных процессов может быть произвольным.

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

#include "mpi.h"
main(int argc, char **argv)
MPI_Init(&argc, &argv); MPI_Finalize() ;

7
Другие параллельные программы на языке Си с использованием технологии MPI можно
найти, например, в Вычислительном полигоне: ссылка: http://polygon.parallel.ru.

MPI_INITIALIZED(FLAG, IERR) LOGICAL FLAG INTEGER IERR

Процедура возвращает в аргументе FLAG значение .TRUE., если вызвана из
параллельной части приложения, и значение .FALSE. - в противном случае. Это
единственная процедура MPI, которую можно вызвать до вызова MPI_INIT.

MPI_COMM_SIZE(COMM, SIZE, IERR) INTEGER COMM, SIZE, IERR

В аргументе SIZE процедура возвращает число параллельных процессов в
коммуникаторе сомм.

MPI_COMM_RANK(COMM, RANK, IERR) INTEGER COMM, RANK, IERR

В аргументе RANK процедура возвращает номер процесса в коммуникаторе сомм. Если
процедура MPI_COMM_SIZE ДЛЯ ТОГО же коммуникатора сомм вернула значение SIZE,
то значение, возвращаемое процедурой MPI_COMM_RANK через переменную RANK, лежит в
диапазоне от о до SIZE-1.

В следующем примере каждый запущенный процесс печатает свой уникальный номер
в коммуникаторе MPI_COMM_WORLD И ЧИСЛО процессов в данном коммуникаторе.

program example2
include 'mpif.h'
integer ierr, size, rank
call MPI_INIT(ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
print *, 'process ', rank, ', size ', size
call MPI_FINALIZE(ierr)
end

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

DOUBLE PRECISION MPI_WTIME(IERR) INTEGER IERR

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

8
значению параметра MPI_WTIME_IS_GLOBAL (1 - синхронизированы, 0 - нет).

DOUBLE PRECISION MPI_WTICK(IERR) INTEGER IERR

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

MPI_GET_PROCESSOR_NAME(NAME, LEN, IERR) CHARACTER*(*) NAME INTEGER LEN, IERR

Процедура возвращает в строке NAME имя узла, на котором запущен вызвавший процесс.
В переменной LEN возвращается количество символов в имени, не превышающее
значения константы MPI_MAX_PROCESSOR_NAME. С помощью этой процедуры можно
определить, на какие именно физические процессоры были спланированы процессы
МРI-приложения.

В следующей программе на каждом процессе определяются две характеристики
системного таймера: его разрешение и время, требуемое на замер времени (для
усреднения получаемого значения выполняется NTIMES замеров). Также в данном
примере показано использование процедуры

MPI GET PROCESSOR NAME.
program example3
include 'mpif.h'
integer ierr, rank, len, i, NTIMES
parameter (NTIMES = 100)
character*(MPI_MAX_PROCESSOR_NAME) name
double precision time_start, time_finish, tick
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
call MPI_GET_PROCESSOR_NAME(name, len, ierr)
tick = MPI_WTICK(ierr)
time_start = MPI_WTIME(ierr)
do i = 1, NTIMES
time_finish = MPI_WTIME(ierr)
end do
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
print *, 'processor ', name(1: len), &', process ', rank, ': tick = ', tick, &', time = ', (time_finish-time_start)/
call MPI_FINALIZE(ierr)
end

Задания

Откомпилировать и проверить эффективность выполнения программы
вычисления числа Пи на различном числе процессоров (программа обычно входит
в качестве тестового примера в комплект поставки MPI и может находиться,
например, в файлах /usr/local/examples/mpi/fpi.f или cpi.c ).
Можно ли в процессе работы MPI-программы порождать новые процессы, если в

9
какой-то момент появились свободные процессоры?
Может ли MPI-программа продолжать работу после аварийного завершения
одного из процессов?
Определить, сколько процессов выполняют текст программы до вызова
процедуры MPI_INIT и после вызова процедуры MPI_FINALIZE.
Определить, синхронизованы ли таймеры разных процессов конкретной системы.

10
Доступ онлайн
1 000 ₽
В корзину