Смекни!
smekni.com

Распределенные вычисления на FreePascal под Windows (стр. 1 из 3)

Илья Аввакумов, Freepascal.ru

Введение. О чем эта статья.

Статья посвящена вопросу написания распределенных (параллельных) вычислений с использованием компилятора FreePascal (использовалась версия 2.0.1)

Проблема параллельных вычислений заинтересовала меня совсем не потому что это сейчас модно. Столкнулся с задачей, когда надо было сформировать (для дальнейнего анализа) большой массив данных. Хотелось уменьшить время вычислений имеющимися средствами. Оказывается, организовать параллельные вычисления с использованием моего любимого компилятора — вполне решаемая задача.

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

Идея MPI-программы такова: параллельная программа представляется в виде множества взаимодействующих (посредством коммуникационных процедур MPI) процессов.

Параллельные вычисления требуют

1. Разделения процессов

2. Взаимодействия между ними

MPI (Message Passing Interface) — стандарт на программный инструментарий для обеспечения связи между ветвями параллельного приложения.

В этой статье рассматривается MPICH (MPI CHameleon), свободно распространяемая реализация MPI. Использовалась версия MPICH 1.2.5 для Windows.

Установка и настройка MPICH.

MPICH для Windows требует

1. Windows NT4/2000/XP ( Professional или Server). Под Win9x/ME работать не станет!

2. Сетевое соединение по протоколу TCP/IP между машинами.

Сразу обговорю, что все примеры тестировались на двух машинах, объединенных в локальную сеть. Один компьютер (сетевое имя ILYA) — мой, а второй (сетевое имя EKATERINA) — жены.

Установка.

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

Для установки нужно

1. Скачать mpich.nt.1.2.5.src.exe (5278 Кб) или mpich.nt.1.2.5.src.zip (5248 Кб)

Либо с официальной страницы MPICH

http://www.mcs.anl.gov/mpi/mpich/download.html

Либо с ftp сервера ftp.mcs.anl.gov/pub/mpi/nt.

2. Если запустить exe файл, то после распаковки запустится интерактивная программа установки MPICH. Чтобы не утомлять себя выбором устанавливаемых компонент, удобнее установить MPICH в неинтерактивном режиме.

Для этого

а. Разархивируйте содержимое в общую папку (например, \ILYA\common)

b. Отредактируйте файл setup.iss

c. Строка

szDir=C:\Program Files\MPICH

определяет каталог, куда установится MPICH. Это расположение можно изменить.

d. Строки

Component-count=7

Component-0=runtime dlls

Component-1=mpd

Component-2=SDK

Component-3=Help

Component-4=SDK.gcc

Component-5=RemoteShell

Component-6=Jumpshot

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

Component-count=4

Component-0=runtime dlls

Component-1=mpd

Component-2=SDK

Component-3=Help

Для простого компьютера (которому отводится только роль вычислителя) число компонент может быть сокращено до двух.

Component-count=2

Component-0=runtime dlls

Component-1=mpd

На каждом компьютере кластера выполнить команду установки в неинтерактивном режиме. В моем случае запуск программы установки таков:

>\ILYA\common\setup -s -f1\ILYA\common\setup.iss

После установки на каждом компьютере должна запуститься служба mpich_mpd (MPICH Daemon (C) 2001 Argonne National Lab). (смотрите рисунок)

Если был установлен компонент SDK (что необходимо сделать на том компьютере, откуда будет производиться запуск программ), то в каталоге MPICH (прописанном в пункте szDir) присутствуют подкаталоги SDK и SDK.gcc. Содержимое этих каталогов — библиотечные и заголовочные файлы для языков C, С++ и Fortran.

Каталог SDK предназначен для компиляторов MS VC++ 6.x и Compaq Visual Fortran 6.x, а каталог SDK.gcc — для компиляторов gcc и g77.

Настройка

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

Остановимся подробнее на каталоге mpd\bin в директории MPICH. Содержимое каталога:

mpd.exe исполняемый файл службы mpich_mpd нужна
MPIRun.exe файл, осуществляющий запуск каждой MPI-программы. нужна
MPIRegister.exe программа для шифрования паролей при обмене данными по LAN. иногда полезна
MPDUpdate.exe программа для обновления библиотек MPI не нужна
MPIConfig.exe программа настройки хостов в кластере не нужна
guiMPIRun.exe GUI версия mpirun. не нужна
MPIJob.exe программа для управления MPI-процессами не нужна
guiMPIJob.exe GUI версия mpijob.exe не нужна

Использование команд mpirun и mpiregister ждет нас впереди. Чтобы удостовериться, что службы MPICH, работающие на разных компьютерах, взаимодействуют должным образом, можно воспользоваться утилитой MPIconfig. Для этого следует

1. Запустить MPIConfig.exe (можно воспользоваться ссылкой в главном меню, она там должна быть)

2. Нажать на кнопку "Select"

3. В появившемся окне выбрать пункт меню "Action"—"Scan hosts"

4. Напротив имени каждой машины должна загореться пиктограмма "MPI" ( примерно вот так)

Модуль mpi на FreePascal.

Все вышеописанное относилось к установке собственно MPICH. Для того, чтобы прикрутить библиотеки MPICH к FreePascal, следует еще немножко поработать.

Cледует воспользоваться динамической библиотекой mpich.dll, которая располагается в системном каталоге (копируется туда при установке MPICH).

1. Скачать модуль FreePascal, реализующий функции этой динамической библиотеки. Файл mpi.pp скачать zip-архив (10 КБ)

2. Для использования модуля mpi следует просто скопировать файл mpi.pp в каталог, где FreePascal ищет модули (unit searchpath).

Модуль написан с использованием утилиты h4pas.exe и заголовочных файлов *.h из SDK\Include.

Простейшая MPI программа на FreePascal.

Во именах всех функциях библиотеки MPICH используется префикс MPI_. Возвращаемое значение большинства функций — 0, если вызов был успешным, а иначе — код ошибки.

Основные функции.

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

1 MPI_Init подключение к MPI
2 MPI_Finalize завершение работы с MPI
3 MPI_Comm_size определение размера области взаимодействия
4 MPI_Comm_rank определение номера процесса
5 MPI_Send стандартная блокирующая передача
6 MPI_Recv блокирующий прием

Утверждается, что этого хватит. Причем первые четыре функции должны вызываться только один раз, а собственно взаимодействие процессов — это последние два пункта.

Описание функций, осуществляющих передачу, оставим на потом, а сейчас рассмотрим описание функций инициализации/завершения

function MPI_Init( var argc : longint;

var argv : ppchar) : longint;

Инициализация MPI. Аргументы argc и argv — переменные модуля system, определяющие число параметров командной строки и сами эти параметры, соответственно.

При успешном вызове функции MPI_Init создается коммуникатор ( область взаимодействия процессов), под именем MPI_COMM_WORLD.

function MPI_Comm_size( comm : MPI_Comm;

var nump : longint) : longint;

Определяет число процессов, входящих в коммуникатор comm.

function MPI_Comm_rank( comm : MPI_Comm;

var proc_id : longint) : longint;

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

functionnn MPI_Finalize : longint;

Завершает работу с MPI.

Порядок вызова таков:

1. MPI_Init — подключение к MPI

2. MPI_Comm_size — определение размера области взаимодействия

3. MPI_Comm_rank — определение номера процесса

4. Далее идет любая совокупность команд обмена (передача, прием, и тп.)

5. MPI_Finalize — завершение работы с MPI

Простейшая MPI программа такова.

test.pas

uses mpi;

var namelen, numprocs, myid : longint;

processor_name : pchar;

begin

MPI_Init( argc, argv);

MPI_Comm_size( MPI_COMM_WORLD, numprocs);

MPI_Comm_rank( MPI_COMM_WORLD, myid);

GetMem( processor_name, MPI_MAX_PROCESSOR_NAME+1); // константа MPI_MAX_PROCESSOR_NAME равна 256

namelen := MPI_MAX_PROCESSOR_NAME;

MPI_Get_processor_name( processor_name, namelen);

Writeln('Hello from ',myid,' on ', processor_name);

FreeMem(processor_name);

MPI_Finalize;

end.

Здесь, как видно, никакого обмена нет, каждый процесс только "докладывает" свой ранг.

Для наглядности выводится также имя компьютера, где запущен каждый процесс. Для его определения используется функция MPI_Get_processor_name.

function MPI_Get_processor_name( proc_name : Pchar;

var name_len : longint) : longint;

При успешном вызове этой функции переменная proc_name содержит строку с именем компьютера, а name_len — длину этой строки.

После компиляции (с соответствующими опциями)

>fpc -dRELEASE [-Fu<каталог, где размещен файл mpi.pp>] test.pas

должен появиться исполняемый файл test.exe, однако рано радоваться. Запуск этого exe-файла не есть запуск параллельной программы.

Запуск MPI-программы.

Запуск MPI-программы осуществляется с помощью загрузчика приложения mpirun. Формат вызова таков:

>mpirun [ключи mpirun] программа [ключи программы]

Вот некоторые из опций команды mpirun:

-np x
запуск x процессов. Значение x может не совпадать с числом компьютеров в кластере. В этом случае на некоторых машинах запустится несколько процессов. То, как они будут распределены, mpirun решит сам (зависит от установок, сделанных программой MPIConfig.exe)
-localonly x
-np x -localonly
запуск x процессов только на локальной машине
-machinefile filename
использовать файл с именами машин
-hosts n host1 host2 ... hostn
-hosts n host1 m1 host2 m2 ... hostn mn
запустить на n явно указанных машинах. Если при этом явно указать число процессов на каждой из машин, то опция -np становится необязательной
-map drive: &bsol;host&bsol;share
использовать временный диск
-dir drive:&bsol;my&bsol;working&bsol;directory
запускать процессы в указанной директории
-env "var1=val1|var2=val2|var3=val3..."
присвоить значения переменным окружения
-logon
запросить имя пользователя и пароль
-pwdfile filename
использовать указанный файл для считывания имени пользователя и пароля.Первая строка в файле должна содержать имя пользователя, а вторая — его пароль)
-nocolor
подавить вывод от процессов различным цветом
-priority class[:level]
установить класс приоритета процессов и, опционально, уровень приоритета.class = 0,1,2,3,4 = idle, below, normal, above, high level = 0,1,2,3,4,5 = idle, lowest, below, normal, above, highest
по умолчанию используется -priority 1:3, то есть очень низкий приоритет.

Для организации параллельного вычисления на нескольких машинах следует