[ на главную ]

Использование технологии
параллельного программирования 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, размер интервала, на котором считали сумму, равен 10 8

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
При использовании материалов этого сайта, пожалуйста вставляйте в свой текст ссылку на мою статью.