Лабораторные работы

advertisement
Лабораторные работы
Пособие предназначено для освоения практического курса параллельного программирования с
использованием технологии MPI. В настоящее время технология MPI является основным средством
программирования для кластерных систем и компьютеров с распределенной памятью, но может применяться
также и на вычислительных системах другого типа.
Лабораторный цикл по дисциплине «Параллельное программирование» включает в себя следующие работы
1.
2.
Компиляция программ, использующих интерфейс MPI.
Использование функции групповой рассылки данных
Реализация и настройка кластера интерфейса MPI
в среде MS Windows 9x/NT/XP
Проверить наличие работающей сети компьютеров, какие из них
a
могут быть использованы для кластера. Запомнить/записать их
c
имена/IP.
Создать на одном компьютере общую папку для доступа из сети.
Дать доступ для неё всем на чтение/запись. В данной папке
будут находится все программы, которые будут запускатся в
параллельном режиме. Так же нужно будет скопировать в
данную папку дистрибутив MPICH: mpich.nt.1.2.5.exe (5 404 672
d
байта). Где его взять – можно спросить у лаборантов.
Запустить на каждом нужном компьютере данный файл.
Инсталляцию провести в обычном режиме. После окончания
инсталляции – убедится что сервис mpd.exe запущен. Для этого
нажать Ctrl+Shift+Esc – перейти на вкладку процессов – и найти процесс
mpd.exe. Если нет – запустить «Сервисы» из меню администрирования, и
запусить службу вручную. Либо попробовать просто перезагрузится.
После того как служба была запущена, требуется установить единые настройки
для всех узлов. Для этого запускаем MPIConfig.exe. (по умолчанию она
находится в меню пуск: MPICH->mpd->MPICH Configuration tool. Либо в
b
%PROGRAMFILES%\MPICH\mpd\bin\MPIConfig .exe).
В появившемся окне – 1) добавить все машины, которые являются узлами
кластера.
Можно проверить наличие связи между ними – выбрав галку Show configuration,
и выбирая хосты из списка слева, убедится, что служба mpd на всех хостах
запущена – и видится с данного компьютера.
Потом следует в группе 2) нажать на галку сверху, для выбора всех пунктов
настройки. Настройки можно оставить по умолчанию, т.к. ничего менять не
стоит.
После этого следует нажать кнопку “Apply”. И убедиться, что настройки
применились для всех хостов. Признаком проблем может быть длительная
пауза при применении к какому нибудь хосту. Требуется проверить данный хост
на наличие проблем.
После этих процедур – можно считать, что кластер настроен на использование.
Проверить работоспособность кластера. Проверить можно с помощью программы hello.exe, исходный
код которой нужно будет взять из примера к лабораторной работе № 1. Для этого, требуется
скопировать скомпилированный файл hello.exe в общую папку (созданную в п.2). Внимание! для
компиляции для NT систем, требуется Microsoft Visual C++ 6.0 либо gcc для win32.
После того как программа скопирована в папку, запускаем её 2 способами:
С командной строки: для запуска программы с командной строки используется программа mpirun.exe. Её
синтаксис такой:
#> mpirun –np <количество процессов> -logon //компьютер/папка/cpi.exe
Пример
Пример выполнения программы hello.exe:
%PROGRAMFILES%\MPICH\mpd\bin>mpirun -np 2 -logon \\12izlab2\mpi\hello.exe
Mpd needs an account to launch processes with:
account (domain\user): admin
password:
Hello world from process 1 of 2 at 11izlab2.
Hello world from process 0 of 2 at 12izlab2.
С помощью графического интерфейса guiMPIRun.exe (его можно обнаружить там же, где и находятся
остальные файлы MPICH) можно запустить на выполнение созданное приложение на сконфигурированном ранее кластере.
2
Примечания
Помните, что для запуска или просто для входа на другой компьютер требуется иметь права,
достаточные для выполнения приложений на нем. То есть – вам необходимо вводить login и пароль при
запуске программ на кластере. Для варианта с командной строкой – указывается параметр –login. Так
же, имеется возможность указывать эту пару автоматически. Для этого используется –pwdfile <имя
файла>. В указанном файле, в первой строке должен быть логин, во второй строке – пароль. Помните,
что Данным способом нужно пользоваться очень аккуратно и осторожно, т.к. ваш пароль для доступа на
машину может стать известен другим лицам.
Для графической оболочки – пароль запрашивается при первом запуске программы на кластере. Если
пароль не запрашивается, но требуется – следует установить галку «Always prompt for password», в окне,
вызываемом по кнопке Advanced Options.
Показателем того, что требуется пароль или он введен неправильно служит следующее сообщение:
Рекомендуемая литература
1. Немнюгин С.А., Стесик О.Л. Параллельное программирование для многопроцессорных
вычислительных систем. – Спю.: БХВ-Петербург, 2002.
2. А. С. Антонов «Введение в параллельные вычисления»
http://parallel.ru/tech/tech_dev/antonov.pdf
3. А. С. Антонов «Практический курс MPI»
http://parallel.ru/tech/tech_dev/MPIcourse/
Русскоязычная страница МРI
http://parallel.ru/tech/tech_dev/mpi.html
Стандарт MPI-1.1 (на английском)
http://parallel.ru/docs/Parallel/mpi1.1/mpi-report.html
4. Воеводин Вл.В. Лекция по MPI
http://parallel.ru/vvv/mpi.html
MPICH official page
http.//www-unix.mcs.anl.gov/mpi/mpich/
MPI:The Complete Reference
http://www.netlib.org/utk/papers/mpi-book/mpi-book/html
3
Лабораторная работа № 1
Компиляция программ, использующих интерфейс MPI
1. Подготовка к работе
Необходимо иметь в наличие работающий кластер на базе MPICH. Так же необходимо иметь пакет
разработки MS Visual C++ 6.0 или более новую версию.
2. Контрольные вопросы
Что должно выполняться на компьютере, чтобы он мог быть хостом кластера?
Чем является хост кластера?
Как происходит настрофка хостов кластера?
Поясните назначение каждой MPI функции в программе Hello world.
Поясните ход работы данной программы.
Зачем данной программе требуется библиотека mpich.lib и заголовок mpi.h ?
Объясните, чем технологически отличается данная программа, от любой другой не MPI
программы.
8. Чем отличается Release версия от Debug и зачем нужно такое разделение?
9. Что предоставляет SDK из поставки MPICH?
1.
2.
3.
4.
5.
6.
7.
3. Задание
Скомпилировать программу "Hello world" с использованием MPI интерфейса
Программа должна Вывести "Hello world" от каждого процесса. Так же надо будет вывести номер
процесса и имя компьютера, на котором этот процесс запущен.
Для этого требуется написать программу с использованием следующих функций MPI:
MPI_Init
Для запуска MPI интерфейса
MPI_Comm_size
Для получения количества процессов в кластере
MPI_Comm_rank
Для получения номера процесса в кластере
MPI_Get_processor_name
Для получения имени компьютера, на котором находится процесс
MPI_Finalize
Для завершения работы с MPI
Для этого необходимо скомпилировать ниже приведенный листинг программы в пакете MS Visual C++
4. Методические указания
Для компиляции данной программы, мы будем использовать Microsoft Visual С++ 6.0.
Для начала следует создать новый проект.
FileNew… Во вкладке Projects выбирается Win32 console application. После чего пишется название
проекта (hello), и путь к файлам.
Выбирается Empty Project.
В проект требуется добавить пустой файл. Нажмите FileNew… выбираем C++ Source File и даем ему
имя “hello”.
После этого – переписываем листинг программы в данный файл.
Теперь следует установить пути до файлов mpi.h и до mpich.lib
Заходим в свойства проекта (Alt+F7), выбираем вкладку C/C++, категорию Preprocessor, и в строку
Additionals include directories, вводим путь до include файлов. Обычно путь выглядит как
%PROGRAMFILES%\mpich\sdk\include\.
Переходим во вкладку Link, в строке Object/library modules необходимо ввести имя библиотеки mpich.lib.
В этой библиотеке хранятся все функции вызовов MPI интерфейса.
После, в этом же окне, переходим к вкладке Input. В строке Additional library path: вводим путь к
директории с файлами *.lib библиотеки MPICH. Они находятся по тому же пути что и заголовки:
%PROGRAMFILES%\mpich\sdk\lib
Далее – запускаем компиляцию проекта. Для этого нажимаем F7. В результате, в окошке Build должно
быть примерно следующее:
--------------------Configuration: hello - Win32 Debug-------------------Compiling...
hello.cpp
Linking...
hello.exe - 0 error(s), 0 warning(s)
Если у вас то же самое – значит программа скомпилирована успешно.
Скопируем файл hello.exe из папки Debug в папке вашего проекта, и скопируем его в общую папку для
параллельных программ.
Запускаем данную программу – согласно с указаниями, данными в первой л/р.
Настройте и скомпилируйте Release вариант программы. Данный релиз не должен содержать никакой
4
отладочной информации, а так же должен быть максимально оптимизирован
4. Листинг программы
// программа выводит Hello world от всех процессов
#include <stdio.h>
#include “mpi.h”
int main(int argc, char * argv[])
{
int rank, size, resultlen;
char name[MPI_MAX_PROCESSOR_NAME];
MPI_Init( &argc, &argv );
MPI_Comm_size( MPI_COMM_WORLD, &size );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Get_processor_name(name, &resultlen);
printf( "Hello world from process %d of %d at %s\n", rank, size, name);
MPI_Finalize();
return 0;
};
5. Примечания
При выполнении программы можно заметить, что порядок процессов соблюдается не всегда. Он может
быть произволен. Это нормально для простых случаев, но если вашему алгоритму будет важен порядок
получения результатов – нужно будет использовать схему master/slave.
Для получения результата от всех процессов нужно, при вызове функций MPI, использовать тег
MPI_COMM_WORLD при указании аргументов функциями.
Полный справочник функций вы можете изучить в приложении к данному методическому пособию.
5
Лабораторная работа № 2
Использование функции групповой рассылки данных
1. Подготовка к работе
Необходимо иметь работающий кластер на базе MPICH, умение компилировать программы в MS Visual
C++, знание языка C.
2. Контрольные вопросы
1. Почему для выполнения параллельной программы требуется знать пароль для доступа на все
компьютеры?
2. Почему для выпоолнения параллельной программы она должна находиться на общедоступном
для всего кластера ресурсе?
3. Чем отличается синхронная передача, от асинхронной?
4. Чем отличается групповая рассылка данных – от точечной?
5. Почему требуется очищать файловый буфер при использовании printf()?
6. Для чего служит функция MPI_Barrier()?
7. Можно ли передать строку так же как и цифру, используя MPI_Bcast()?
3. Задание
Необходимо реализовать программу, процессы которой обмениваются данными, введенными
пользователем.
MPI_Init()
процесс=0
НЕТ
ДА
Ввод числа
MPI_Bcast()
Вывод числа на экран
НЕТ
Число<=0
ДА
MPI_Finalize()
4. Методические указания
В данной программе необходимо обеспечить обмен данными между нулевым процессом и всеми
остальными. Это делается с помощью MPI функции MPI_Bcast.
Нулевой процесс запрашивает символ от пользователя, после получения которого, рассылает его всем
процессам. После этого каждый процесс должен распечатать полученное сообщение с указанием своего
номера и имени. Процесс ввода может продолжаться до получения пустой строки.
Программа должна соответствовать данной блок схеме:
Пример выполнения программы
Пример результата выполнения данной программы:
%PROGRAMFILES%\MPICH\mpd\bin>mpirun -np 2 -logon \\12izlab2\mpi\lab3.exe
Mpd needs an account to launch processes with:
account (domain\user): admin
password:
Enter a digit (0 or less to exit):456
Process 0 (12izlab2.) got 456
Process 1 (11izlab2.) got 456
Enter a digit (0 or less to exit):598
Process 0 (12izlab2.) got 598
Process 1 (11izlab2.) got 598
Enter a digit (0 or less to exit):666
Process 0 (12izlab2.) got 666
Process 1 (11izlab2.) got 666
Enter a digit (0 or less to exit):-100
6
Process 0 (12izlab2.) got -100
Process 1 (11izlab2.) got -100
%PROGRAMFILES%\MPICH\mpd\bin>
5. Примечания
Используйте функцию fflush(stdout) после вызова printf(). Иначе вы можете и не увидеть вывод на
экран во время ввода и обработки данных, в противном случае увидите только после окончания работы
программы. Это связано с тем, что текст, подаваемый на stdout – буферизуется, что приводит к тому, что
вывод от удаленного хоста не приходит на консоль компьютера, с которой был осуществлен запуск.
Функция fflush() принудительно сбрасывает буфер для stdout.
Иногда можно заметить, что ответ от удаленного хоста приходит со значительным опозданием, т.е. уже
после прохождения цикла, во время ожидания ввода следующего числа. Это происходит, потому что
функция MPI_Bcast() является буферной, т.е. после выполнения, управление программы сразу же
передается следующему оператору, а передаваемое сообщение заносится в специальный буфер для
передачи. В результате, мы можем сразу же после отработки MPI_Bcast() изменять содержимое буфера.
Это позволяет рассылать сообщения и другим хостам или продолжать дальнейшую работу, не ожидая
ответа удаленного хоста. Данные задержки могут быть связанны с загруженностью сети, или удаленного
хоста. Чтобы программа ожидала окончания работы каждого узла – можно использовать синхронные
функции передачи (с подтверждением). А можно, после рассылки всем процессам нужных данных, перед
запуском параллельной обработки, использовать функцию MPI_Barrier(comm). Данная функция не
возвращает управления, пока передачи между процессами не закончатся. Так же не стоит забывать,
что передача данных происходит не только всем остальным хостам, но и хосту-отправителю. Поэтому
функцию получения данных необходимо разместить и в блоке (обычно для ведущего хоста) откуда был
вызван MPI_Bcast().
7
Приложение А
Основные понятия
Наиболее распространенной технологией программирования для параллельных компьютеров с
распределенной памятью в настоящее время является MPI. Основным способом взаимодействия
параллельных процессов в таких системах является передача сообщений друг другу. Это и отражено в
названии данной технологии – Message Passing Interface (интерфейс передачи сообщений). Стандарт
MPI фиксирует интерфейс, который должен соблюдаться как системой программирование на каждой
вычислительной платформе, так и пользователем при создании своих программ. Самый
распространенной версией является MPI 1.1 разработанной в 1998 г.
MPI поддерживает работу с языками Фортран и Си. Полная версия интерфейса содержит более 125
процедур и функций.
Интерфейс поддерживает создание параллельных программ в стиле MIMD (Multiple Instruction Multiple
Data), и SPMD-модель (Single Program Multiple Data).
MPI-программа – это множество параллельных взаимодействующих процессов. Все процессы
порождаются один раз на все время выполнения программы. Процессы не имеют общих переменных
или данных и работают в своих собственных адресных пространствах. Основным способом
взаимодействия между процессами является явная посылка сообщений.
Коммуникатор – это группа процессов объединенных в одну среду общения. Их состав произволен и они
могут пересекаться. Процессы могут взаимодействовать только внутри одного коммуникатора, тем
самым сообщения, отправленные в разных коммуникаторах не пересекаются и не мешают друг другу.
Все процессы имеют доступ к предопределенному коммуникатору MPI_COMM_WORLD, который
существует во все время выполнения работ, для взаимодействия всех запущенных процессов MPIпрограммы.
Номер процесса – целое неотрицательное число – уникальный идентификатор процесса в
коммуникаторе. Данный номер является адресом процесса, с помощью которого ему можно посылать
сообщения. У процесса может быть несколько номеров в разных коммуникаторах. Если коммуникатор
содержит n процессов то номер любого процесса лежит в пределах от 0 до n-1.
Тем самым коммуникатор и номер коммуникатора являются двумя основными атрибутами процесса.
Основным способом общения процессов между собой является явная посылка сообщений. Сообщение
– набор данных некоторого типа, которые имеют несколько атрибутов, включая номер процесса
отправителя, получателя, идентификатор сообщения и др.
Идентификатор (тег) – по нему процесс принимающий сообщения может различить два сообщения
пришедшие с одного и того же процесса. Представляет собой неотрицательное число.
В последнем аргументе сообщения большинство процедур MPI возвращает информацию об
успешности завершения. В случае успешного выполнения возвращается MPI_SUCCESS, иначе код
ошибки.
8
Приложение В
Краткий справочник функций MPI
Процедуры инициализации
Функция
Описание
Аргументы
MPI_Init(*argc,*argv)
MPI_Comm_size(comm,*size)
Процедура инициализации MPI интерфейса. Должна
вызываться до первой любой MPI фунции
Получает число процессов в коммуникаторе
MPI_Comm_rank(comm,*rank)
Получет номер процесса
MPI_Abort(comm,errorcode)
Аварийный выход из MPI программы
MPI_Get_processor_name(*name,*resultlength)
Получить имя хоста
MPI_Initialized (*flag)
Индикация прохождения инициализации MPI
интерфейса
Получить время в секундах, прошедшее с начала суток
Остановка MPI интерфейса и отчистка памяти
программы. Должна вызыватся в любой MPI программе.
После неё вызывать MPI функции нельзя (включая
MPI_Init())
Аргументы, переданные программе
при запуске
Номер коммуникатора, переменная
для хранения результата
Номер коммуникатора, переменная
для хранения результата
Номер коммуникатора, номер
ошибки при выходе
Буфер для хранения строки с
именем, число символов в буфере
Флаг состояния (1-успешно, 0 –
ошибка)
MPI_Wtime ()
MPI_Finalize ()
Сообщения «точка-точка»
Функция
Описание
Аргументы
MPI_Send(buffer,count,type,dest,tag,comm)
Посылка сообщения с блокировкой
MPI_Isend(buffer,count,type,dest,tag,comm,request)
Посылка сообщения без блокировки
(асинхронная посылка)
Посылка сообщения с синхронизацией
Посылка сообщения с буферизацией данных
Буфер, количество элементов в
буфере, тип данных в буфере,
получатель, идентификатор,
коммуникатор
->>-, возвр. Статус
MPI_Ssend (*buf,count,datatype,dest,tag,comm,ierr)
MPI_Bsend (*buf,count,datatype,dest,tag,comm)
MPI_Recv(buffer,count,type,source,tag,comm,status)
MPI_Irecv(buffer,count,type,source,tag,comm,request)
MPI_Rsend (*buf,count,datatype,dest,tag,comm)
MPI_Buffer_attach (*buffer,size)
MPI_Buffer_detach (*buffer,size)
->>-
Получение сообщения с блокировкой
Получение сообщения без блокировки
(асинхронное получение)
Отправление по готовности.
->>->>-
Установка буфера для асинхронных и
буферных пересылок
Освобождения буфера для асинхронных и
буферных пересылок
Комбинированный вариант. Одновременная
отсылка и получение информации.
Буфер, размер буфера
->>-
-->>--
Проверка на блокировки. Возвращает состяние
блокировок.
Буфер отправляемой информации,
количество отпр. Информации, тип
отпр. Инф., получатель, таг
отправителя, то же самое для
получения.
Получатель, таг, коммуникатор,
статус
Функция
Описание
Аргументы
MPI_Barrier (comm)
Коммуникатор
MPI_Bcast (*buffer,count,datatype,root,comm)
Приостановка программы до окончания всех
групповых обменов данными.
Групповая рассылка данных. Данные в буфере
рассылаются все остальным процессам в
коммуникаторе
MPI_Scatter (*sendbuf,sendcnt,sendtype,*recvbuf,
...... recvcnt,recvtype,root,comm)
Рассылает еденичные сообщения для каждого
процесса из буфера
MPI_Gather (*sendbuf,sendcnt,sendtype,*recvbuf,
...... recvcount,recvtype,root,comm)
Собирает еденичные сообщения от процессов
в буфер.
MPI_Reduce
(*sendbuf,*recvbuf,count,datatype,op,root,comm)
Выполняет групповую операцию над буфером
в каждой переменной
MPI_Allreduce
Выполняет групповую операцию над буфером
MPI_Sendrecv (*sendbuf,sendcount,sendtype,dest,sendtag,
*recvbuf, recvcount, recvtype, source, recvtag,
comm,*status)
MPI_Probe (source,tag,comm,*status)
Групповые сообщения
Буфер, количество элементов в
буфере, тип данных в буфере,
процесс-отправитель,
коммуникатор
Буфер, количество элементов в
буфере, тип данных в буфере,
тоже для получателя, процесс
отправитель, коммуникатор.
Буфер, количество элементов в
буфере, тип данных в буфере,
тоже для получателя, процесс
отправитель, коммуникатор.
Буфер, количество элементов в
буфере, тип данных в буфере,
операция, процесс отправитель,
коммуникатор.
Буфер, количество элементов в
9
(*sendbuf,*recvbuf,count,datatype,op,comm)
и рассылает результаты всем процессам
буфере, тип данных в буфере,
операция, процесс отправитель,
коммуникатор.
Типы пересылаемых данных
Тип в MPI
MPI_CHAR
MPI_SHORT
MPI_INT
MPI_LONG
MPI_UNSIGNED_CHAR
MPI_UNSIGNED_SHORT
MPI_UNSIGNED
MPI_UNSIGNED_LONG
MPI_FLOAT
MPI_DOUBLE
MPI_LONG_DOUBLE
MPI_BYTE
MPI_PACKED
Соответствующий тип в Си
signed char
signed short int
signed int
signed long int
unsigned char
unsigned short
unsigned int
unsigned long int
float
double
long double
8 бит
Данные, упакованные с помощью MPI_Pack()
Аргументы
Аргумент
Буфер (buffer)
Тип
*char
Количество( Count)
Тип (type)
Получатель
(destination)
Таг (tag)
Unsigned long
MPI_TYPE
Unsigned long
Коммуникатор
(comm)
Статус (status)
Unsigned long
Запрос (request)
10
Unsigned long
Struct
MPI_STATUS
Struct
MPI_REQUEST
Описание
Указатель на буфер, где хранятся пересылаемые данные. Должен выделяться до вызова функций с
помощью malloc
Количество элементов в буфере. Например длина текстовой строки.
Тип передаваемых данных. См. предыдущую таблицу
Номер процесса-получателя. Если получатель не важен или нужен всем MPI_ANY_SOURCE
Идентификатор сообщения. Должен совпадать в функциях отправки и функции, которая получает
отправленные данные. Если это не важно или не нужно – используется тег MPI_ANY_TAG
Номер коммуникатора. Если сообщение требуется разослать всем процессам – используется
MPI_COMM_WORLD
Структура, содержащая статус выполненной функции. Формат можно посмотреть в файле mpi.h
Структура для асинхронных операций пересылки. С помощью неё можно в дальнейшем проверить
состояние пересылаемого сообщения.
Download