на главную ] 

Использование технологии
параллельного программирования MPI-2

Е.С.Борисов

понедельник, 6 марта 2006 г.


1 Введение

Существуют задачи, не решаемые на серийных персональных компьютерах за приемлемое время[1], к примеру прогнозирование погоды, моделирование процессов разрушения в механике (crash-тесты).

Рис 1: Средства параллельных вычислений
уровень 2:
средства автоматизированного
распараллеливания
(Adaptor, Bert77)
уровень 1:
коммуникационные библиотеки
(MPI, PVM, OpenMP)
уровень 0:
аппаратура
(SMP, MPP, Кластеры)
Для решения таких задач используют многопроцессорные (параллельные) вычислители, множество архитектур которых весьма обширно. Для параллельных вычислительных систем необходимо создавать специальные программы. В тексте такой программы определяются части (ветки), которые могут выполнятся параллельно, а также алгоритм их взаимодействия. Параллельные программы, вообще говоря, являются архитектурно зависимыми. Средства параллельных вычислений можно разделить на три уровня (рис.1).

1.1 Аппаратные средства для параллельных вычислений

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

Рис.2: Система с общей памятью
\includegraphics[origin]{images/smp.ps}
Системы с общей памятью - все процессоры работают в едином адресном пространстве с равноправным доступом к памяти(рис.2). В эту группу попадают симметричные мультипроцессорные системы(SMP). В таких системах наличие общей памяти упрощает взаимодействие процессоров между собой, однако возникает необходимость в механизме разрешения конфликтов между процессорами за доступ к памяти, что накладывает сильные ограничения на число процессоров (обычно не более 32). Таким образом, при всем удобстве использования, производительность систем с общей памятью ограничена.

Рис.3: Система с распределенной памятью
\includegraphics[origin]{images/mpp.ps}
Системы с распределенной памятью - каждый процессор имеет собственную локальную памятью, и прямой доступ к этой памяти других процессоров невозможен(рис.3). Этой группе принадлежат системы массового параллелизма(MPP) и их менее дорогой вариант кластеры. Такая система обычно состоит из нескольких самостоятельных вычислительных узлов. Для связи узлов используется определенная сетевая технология. Системы с распределенной памятью сложнее программировать, поскольку необходимо делить обрабатываемые данные на части и рассылать их по вычислительным узлам. Общее число процессоров в таких системах теоретически не ограничено.

1.2 Коммуникационные библиотеки

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

1.3 Средства автоматизированного распараллеливания

Параллельные программы можно писать ''вручную'', непосредственно вставляя в нужные места вызовы коммуникационной библиотеки. Этот путь требует от программиста специальной подготовки. Альтернативой является использование систем автоматического и полуавтоматического распараллеливания последовательных программ[4]. Например, Adaptor - одна из реализаций спецификации High Performance Fortran (HPF) или BERT77 - средство автоматического распараллеливания Fortran-программ. Такие системы так же могут помочь пользователю выяснить, можно ли распараллелить данную задачу, оценить время ее выполнения, определить оптимальное число процессоров.

2 Кластерные системы и стандарт параллельного программирования MPI

Кластерные системы приобретают все большую популярность. У этого класса параллельных вычислительных систем есть существенные преимущества перед другими архитектурами вычислителей.

2.1 Стандарт MPI

Для программирования кластеров применяются библиотеки построенные по модели обмена сообщениями. Основным стандартом здесь является MPI : Message Passing Interface [5]. На настоящий момент существуют две основные версии этого стандарта: MPI-1 и MPI-2, причем MPI-1 является частным случаем MPI-2. Стандарт MPI-1 описывает статическое распараллеливание, т.е. количество параллельных процессов фиксировано. Он позволяет описывать обмены типа точка-точка, широковещательные(коллективные) обмены, групповые обмены а также позволяет организовывать топологии взаимодействия процессов. Стандарт MPI-2 помимо функциональности MPI-1 содержит возможность динамического порождения процессов и управления ими.

Разными коллективами разработчиков написано несколько программных пакетов, удовлетворяющих спецификациям MPI (MPICH, MPICH2, LAM, OpenMPI, HPVM, etc.). Существуют стандартные ''привязки'' MPI к языкам С, С++, Fortran 77/90, а также реализации почти для всех суперкомпьютерных платформ и сетей рабочих станций.

2.2 Запуск MPI-2 на кластере

В данной работе для экспериментов был использован кластер на основе сети персональных компьютеров и библиотека MPICH2 [6]. Этот пакет можно получить и использовать бесплатно. В состав MPICH2 входит библиотека программирования, загрузчик приложений, утилиты.

  1. Прежде всего необходимо скачать и установить на все узлы кластера пакет MPICH2. Исходные тексты или уже скомпилированные пакеты под разные платформы можно получить на сайте [6].

    В данном случае MPICH2 v.1.0.3 собирался из исходных текстов для ОС FreeBSD v.5.3 на процессоре Intel Pentium III. Процесс инсталляции библиотеки описан в MPICH2 Installer's Guide.

  2. MPICH2 использует rsh (remote shell). Поэтому необходимо запустить на каждом узле rshd (remote shell server) и согласовать права доступа, т.е. по команде rsh mynode система должна сразу ''пускать'' вас не спрашивая пароль. Для обеспечения более высокого уровня сетевой безопасности можно использовать ssh - OpenSSH remote login client.

  3. Компиляция MPI-программы на языке С выполняется утилитой mpicc, представляющей собой надстройку над C-компилятором, установленным в данной ОС. Так же есть аналогичные утилиты для языков С++ - mpiCC и FORTRAN77 - mpif77.
    mpicc myprog.c -o myprog
    mpiCC myprog.cpp -o myprog
    mpif77 myprog.f -o myprog
    

  4. Перед запуском ''бинарника'' myprog необходимо разослать его на все узлы кластера, причем локальный путь до myprog должен быть одинаковый на всех машинах, например - /usr/mpibin/myprog.

    Вместо процедуры копирования программы на узлы можно использовать NFS (Network File System) :

    • на головной машине запускаем NFS-сервер и открываем каталог с myprog
    • на каждом рабочем узле кластера, монтируем NFS головной машины, используя единый для всех узлов локальный путь.

  5. В отличии от MPICH1, который использовал только rsh, в случае MPICH2 процессы на узлах управляются специальным демоном mpd. Перед началом работы надо запустить его с головной машины на всех узлах при помощи mpdboot.

    mpdboot --totalnum=2 --file=hosts.mpd --user=mechanoid --verbose
    

    где hosts.mpd - текстовый файл со списком используемых узлов кластера.

    Проверка состояния mpd выполняется при помощи mpdtrace:

    $ mpdtrace -l
    node2.home.net_51160 (192.168.0.2)
    node1.home.net_53057 (192.168.0.1)
    

    Завершение работы mpd выполняется при помощи mpdexit

    $ mpdexit node2.home.net_51160
    

    При выключении одного узла выключаются все остальные.

  6. Запуск MPI-программы производится командой :

    mpiexec -n N myprog
    

    где N - начальное количество параллельных процессов.

    После этого происходит запуск N копий MPI-программы myprog.

    mpiexec сам распределяет процессы по узлам, ''общаясь'' с mpd, в данном случае нет надобности указывать список узлов как в mpirun для MPICH1.

2.3 Статическая параллельная программа с использованием MPI

Параллельная программа описывает некоторое количество процессов (веток параллельной программы) и порядок их взаимодействия. В статической модели стандарта MPI-1 количество таких веток фиксировано и задается при запуске программы.

MPI-программа начинается с вызова функции MPI_INIT(), которая включает процесс в среду MPI, и завершается вызовом функции MPI_FINALIZE(). При запуске каждая ветка параллельной программы получает MPI-идентификатор - ранг, который можно узнать при помощи функции MPI_COMM_RANK(). Для обмена данными между процессами в рамках MPI существует много разных функций: MPI_SEND() - обмен точка-точка, посылка сообщения для одного процесса, MPI_RECV() - обмен точка-точка, прием сообщения, MPI_BCAST() - широковещательная посылка один-всем, MPI_REDUCE() - сбор и обработка данных, посылка все-одному и еще много других.

Приведем пример статической MPI-программы вычисления числа $ \pi$ как суммы ряда на языке FORTRAN77, текст программы [здесь].

Результаты работы программы, на кластере из двух PC на процессоре Pentium III 700MHz, сеть FAST ETHERNET 100Mbs, размер интервала, на котором считали сумму, равен 108

2.4 Динамическая параллельная программа с использованием MPI

Теперь займемся динамическим порождением процессов. Стандарт MPI-2 предусматривает механизмы порождения новых ветвей из уже запущенных в процессе выполнения параллельные программы. В MPI-2 это происходит путем запуска файлов программ (аналогично функциям exec() стандарта POSIX.1) с помощью функции MPI_COMM_SPAWN() или MPI_COMM_SPAWN_MULTIPLE(), первая запускает заданное количество копий одной программы, вторая может запускать несколько разных программ.

Запущенные с помощью MPI_COMM_SPAWN процессы не принадлежат группе родителя (MPI_COMM_WORLD) и выполняются в отдельной среде. Порожденные процессы имеют свои ранги которые могут совпадать с рангами группы, в которой выполнялся родительский процесс. Обмен сообщениями между процессами родительской и дочерней групп происходит с использованием так называемого интеркоммуникатора, который возвращается процессу-родителю функцией MPI_COMM_SPAWN(). Дочерние процессы могут получить интеркоммуникатор группы родителя с помощью функции MPI_COMM_GET_PARENT(). Значение интеркоммуникатора используется функциями обмена сообщениями MPI_SEND(), MPI_RECV() и другими.

Приведем пример динамической MPI-программы на языке FORTRAN77. Здесь один родительский процесс порождает три дочерних, затем один дочерний процесс посылает остальным дочерним процессам широковещательное сообщение(MPI_BCAST()), после чего один дочерний процесс посылает сообщение родителю (MPI_SEND()) и принимает от него ответ (MPI_RECV()). Дочерние процессы запускаются родительским с параметром командной строки "--slave", текст программы [здесь].

Результат работы программы:

$ mpiexec -n 1 ./spawn
 master 0 on node2.home.net : start
  slave 1 on node2.home.net : start
  slave 0 on node1.home.net : start
  slave 2 on node1.home.net : start
  slave 1 on node2.home.net : broadcast from  slave 2       
  slave 0 on node1.home.net : broadcast from  slave 2       
  slave 2 on node1.home.net : broadcast from  slave 2       
 master 0 on node2.home.net : message from  slave 2         
  slave 2 on node1.home.net : message from master 0


Литература

1
Задачи для суперкомпьютеров - http://parallel.ru/research/apps.html

2
Основные классы современных параллельных компьютеров - http://parallel.ru/computers/classes.html

3
Коммуникационные библиотеки - http://www.parallel.ru/tech/tech_dev/ifaces.html

4
Средства распознавания параллелизма в алгоритмах - http://www.parallel.ru/tech/tech_dev/auto_par.html

5
Message Passing Interface Forum - http://www.mpi-forum.org

6
MPICH2 - http://www-unix.mcs.anl.gov/mpi/mpich2/index.htm



Evgeny S. Borisov
2006-03-07
При использовании материалов этого сайта, пожалуйста вставляйте в свой текст ссылку на мою статью.