Передача данных отдельным процессам
Федеральное агенство связи
Поволжская государственная академия телекоммуникаций
И информатики
Кафедра программного обеспечения информационных технологий
Методические указания для выполнения
Лабораторных работ по курсу
«Параллельное программирование»
Составители:
Подябин П.П., гр. ПО-01
Юрьев М.В., гр. ПО-02
Цирулин Д.А., гр. ПО-02
Под общей редакцией
Зав.каф.ПОИТ, д.т.н.,проф.
Солодянникова Ю.В.
Рецензент:
Д.ф.-м.н.,
проф. Блатов И.А.
Самара, 2006
Введение
Пособие предназначено для освоения практического курса параллельного программирования с использованием технологии MPI. В настоящее время технология MPI является основным средством программирования для кластерных систем и компьютеров с распределенной памятью, но может применяться также и на вычислительных системах другого типа.
Лабораторный цикл по дисциплине «Параллельное программирование» включает в себя следующие работы
1. Компиляция программ, использующих интерфейс MPI.
2. Использование функции групповой рассылки данных
3. Вычисление числа π
4. Передача данных отдельным процессам.
5. Матричные вычисления.
6. Обмен данными на системе компьютеров с топологией связи «кольцо».
7. Обмен данными на системе компьютеров с топологией связи «линейка».
8. Произведение двух матриц в топологии «кольцо».
9. Решение СЛАУ методом Гаусса.
Реализация и настройка кластера интерфейса MPI
в среде MS Windows 9x/NT/XP
Проверить наличие работающей сети компьютеров, какие из них могут быть использованы для кластера. Запомнить/записать их имена/IP.
Создать на одном компьютере общую папку для доступа из сети. Дать доступ для неё всем на чтение/запись. В данной папке будут находится все программы, которые будут запускатся в параллельном режиме. Так же нужно будет скопировать в данную папку дистрибутив MPICH: mpich.nt.1.2.5.exe (5 404 672 байта). Где его взять – можно спросить у лаборантов.
Запустить на каждом нужном компьютере данный файл. Инсталляцию провести в обычном режиме. После окончания инсталляции – убедится что сервис mpd.exe запущен. Для этого нажать Ctrl+Shift+Esc – перейти на вкладку процессов – и найти процесс mpd.exe. Если нет – запустить «Сервисы» из меню администрирования, и запусить службу вручную. Либо попробовать просто перезагрузится.
После того как служба была запущена, требуется установить единые настройки для всех узлов. Для этого запускаем MPIConfig.exe. (по умолчанию она находится в меню пуск: MPICH->mpd->MPICH Configuration tool. Либо в %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) можно запустить на выполнение созданное приложение на сконфигурирован-ном ранее кластере.
Примечания
Помните, что для запуска или просто для входа на другой компьютер требуется иметь права, достаточные для выполнения приложений на нем. То есть – вам необходимо вводить 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
Лабораторная работа № 1
Компиляция программ, использующих интерфейс MPI
1. Подготовка к работе
Необходимо иметь в наличие работающий кластер на базе MPICH. Так же необходимо иметь пакет разработки MS Visual C++ 6.0 или более новую версию.
2. Контрольные вопросы
1. Что должно выполняться на компьютере, чтобы он мог быть хостом кластера?
2. Чем является хост кластера?
3. Как происходит настрофка хостов кластера?
4. Поясните назначение каждой MPI функции в программе Hello world.
5. Поясните ход работы данной программы.
6. Зачем данной программе требуется библиотека mpich.lib и заголовок mpi.h ?
7. Объясните, чем технологически отличается данная программа, от любой другой не MPI программы.
8. Чем отличается Release версия от Debug и зачем нужно такое разделение?
9. Что предоставляет SDK из поставки MPICH?
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. Листинг программы
// программа выводит 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 при указании аргументов функциями.
Полный справочник функций вы можете изучить в приложении к данному методическому пособию.
Лабораторная работа № 2
Использование функции групповой рассылки данных
1. Подготовка к работе
Необходимо иметь работающий кластер на базе MPICH, умение компилировать программы в MS Visual C++, знание языка C.
2. Контрольные вопросы
1. Почему для выполнения параллельной программы требуется знать пароль для доступа на все компьютеры?
2. Почему для выпоолнения параллельной программы она должна находиться на общедоступном для всего кластера ресурсе?
3. Чем отличается синхронная передача, от асинхронной?
4. Чем отличается групповая рассылка данных – от точечной?
5. Почему требуется очищать файловый буфер при использовании printf()?
6. Для чего служит функция MPI_Barrier()?
7. Можно ли передать строку так же как и цифру, используя MPI_Bcast()?
3. Задание
Необходимо реализовать программу, процессы которой обмениваются данными, введенными пользователем.
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
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().
Лабораторная работа № 3
Вычисление числа π
1. Подготовка к работе
Необходимо иметь в наличие работающий кластер на базе MPICH. Уметь программировать на языке С. Ознакомиться со способом расчета числа π, приведенного в методических указаниях.
2. Контрольные вопросы
1. Может ли параллельная программа работать на гетеродинном класере?
2. Что такое гетеродинный кластер?
3. Чем отличается паралельная программа (с интерфейсом MPI) от обычной программы?
4. Опишите способ расчет числа π использованного в данной лабораторной работе.
5. Назначение функции MPI_Reduce.
6. Назначение функции MPI_Wtime.
7. Почему число периодов желательно задавать числу процессов?
8. Поясните ход программы по блок-схеме.
9. Задание
Написать программу для расчета числа π по указанной блок-схеме.
4. Методические указания
Распределение данных для расчетов и сбор результатов с помощью MPI. В качестве примера, будет взят расчет числа π с помощью разложения элементов ряда.
Число π можно приближенно подсчитать с помощью следующего интеграла: . Данный интеграл можно преобразовать в ряд следующего вида: , или в общем виде . Этот ряд удобен тем, что его члены независимы друг от друга, и значит, их можно считать параллельно. Т.е. нам требуется разбить ряд на m частей (где m- количество хостов в кластере), и считать каждую часть по отдельности. В конце расчетов, m частей суммируются. Число n здесь – это количество рассчитываемых членов, чем оно больше, тем точнее число. При этом для равномерной загрузке всех хостов n желательно делать кратным m. Т.е. Если в расчете участвуют 4 хоста, n должно делиться на 4. Иначе некоторые хосты будут простаивать при последних подсчетах, хотя для малых m – это не скажется на производительности. Расчет можно вести блочно (n/m членов подряд для каждого хоста), или через строчно (n для 1 хоста, n+1, для 2 хоста, …).
Процедуры, которые можно использовать при написании программы:
MPI_Init | Для запуска MPI интерфейса |
MPI_Comm_size | Для получения количества процессов в кластере |
MPI_Comm_rank | Для получения номера процесса в кластере |
MPI_Get_processor_name | Для получения имени компьютера, на котором находится процесс |
MPI_Bcast | Для рассылки количества итераций на все процессы. |
MPI_Reduce | Для сложения рассчитанных частей в одну переменную |
MPI_Wtime | Для получения текущего времени, для подсчета времени выполнения |
MPI_Finalize | Для завершения работы с MPI |
Алгоритм
5. Пример выполнения
Процесс номер 2 запущен на компьютере: 'prog1.'
Процесс номер 0 запущен на компьютере: 'prog2.'
Процесс номер 3 запущен на компьютере: 'prog3.'
Процесс номер 1 запущен на компьютере: 'prog4.'
Введите количество интервалов (n): (0 для выхода) 1024
резульат: pi=3.1415927330626534, Расхождение с эталоном 0.0000000794728603
время работы 0.157488 секунд
Введите количество интервалов (n): (0 для выхода) 100000
резульат: pi=3.1415926535981167, Расхождение с эталоном 0.0000000000083236
время работы 0.011448 секунд
Введите количество интервалов (n): (0 для выхода) 1000000
резульат: pi=3.1415926535899033, Расхождение с эталоном 0.0000000000001101
время работы 0.100975 секунд
Введите количество интервалов (n): (0 для выхода) 10000000
резульат: pi=3.1415926535896856, Расхождение с эталоном 0.0000000000001075
время работы 1.004657 секунд
Введите количество интервалов (n): (0 для выхода) 100000000
резульат: pi=3.1415926535902168, Расхождение с эталоном 0.0000000000004237
время работы 9.993571 секунд
Введите количество интервалов (n): (0 для выхода) 0
6. Примечания
Для замера скорости расчета, следует завести переменную, со временем начала работы, например startwtime = MPI_Wtime();.Данная функция вернет количество прошедших секунд с 01.01.2971. После окончания расчетов, следует получить переменную endwtime = MPI_Wtime();. Разница endwtime-startwtime и будет временем выполнения расчетов в секундах.
У каждого процесса локальная переменная sum – своя, т.е. в ней разные данные. Поэтому складывать функцией MPI_Reduce() надо в другую переменную, например mypi.
Для того чтобы функция MPI_Reduce() складывала, следует указать в аргументе типа функции MPI_SUM.
С полным форматом данных функций можно ознакомится в приложении к данной методичке или на ресурсах, указанных в приложении.
Для выяснения расхождения можно использовать эталон:
double PI25DT = 3.141592653589793238462643; // эталон
Не забывайте использовать fflush(stdout) после printf().
Стандартная инициализация это:
MPI_Init(&argc,&argv); // инициализация параллельного интерфейса
MPI_Comm_size(MPI_COMM_WORLD,&numprocs); // получение количества процессов
MPI_Comm_rank(MPI_COMM_WORLD,&myid); // получение своего номера
MPI_Get_processor_name(processor_name,&namelen);// имя компьютера
Лабораторная работа № 4
Передача данных отдельным процессам
1. Подготовка к работе
Необходимо иметь в наличии кластер на базе MPI. Уметь программировать на языке C. Ознакомиться с функциями точечной отправки сообщений, используя интерфейс MPI, указанными в Приложении.
2. Контрольные вопросы
1. Может ли параллельная программа работать на гетерогенном кластере?
2. Что такое гетерогенный кластер?
3. Чем отличается параллельная программа (с интерфейсом MPI) от обычной программы?
4. Опишите способ расчета числа π, использованного в данной лабораторной работе.
5. Назначение функции MPI_ Reduce.
6. Назначение функции MPI_Wtime.
7. Почему число прериодов желательно задавать числу процессов?
8. Поясните ход программы по блок-схеме.
Задание
Написать программу пересылающую n байтов по цепочке: от нулевого процесса первому процессу, первый процесс ко второму, и так далее. Последний процесс отсылает данные обратно нулевому процессу. При этом требуется замерить время работы полного цикла, а также время пересылки между отдельными процессами.
Методические указания
В начале работы программы организуцется буфер для передачи. Размер буфера должен браться из аргумента ком. Строки, переданной прогроамме при запуске. Под буфер выделяется место в памяти. После этого можно начатьт передавать данные. Нулевой процесс заполняет этот буфер какими либо данными (можно просто нулями) и посылает их первому процессу. Посылка происходит с помощью команды:
MPI_Send ( буфер, размер буфера, MPI_CHAR, 1, 1, MPI_COMM_WORLD).
При этом происходит посылка первому процессу данного буфера. Стоит обратить внимание на идентификацию посылки. Он должен совпадать у отправителя и у получателя.
Остальные процессы должны по цепочке передавать это сообщение друг другу. Т.е. сначала вызывается функция:
MPI_Recv ( буфер, размер буфера, MPI_CHAR, номер пред. процесса, номер процесса MPI_COMM_WORLD, & statuc);
Потом вызывается
MPI_Send ( буфер, размер буфера, MPI_CHAR, номер след.процесса, номер след.процесса, MPI_COMM_WORLD);
Последний процесс отсылает сообщение первому.
Первый процесс получает от посоледнего данные с помощью функции
MPI Recv ( буфер, размер буфера, MPI_CHAR, номер после. процесса, 0, MPI_COMM_WOPLD & status);
Обратите внимание: сообщения отсылаются строго в последовательности передачи, т.е. фукции MPI_Recv(), MPI_Send() выполняются с блокировкой, т.е. программа ждет получения всего буфера.
Алгоритм
Да
Нет
Схема прохождения сигнала
|
|
|
|
Пример выполнения
Посылка данных в цикл (1024 байтов) …
Процесс номер 1 получил 1024 байта от процесса 0 … 0.0001242 сек
Процесс номер 1 получил 1024 байта от процесса 1 … 0.0018743 сек
Процесс номер 1 получил 1024 байта от процесса 2 … 0.0002536 сек
Процесс номер 1 получил данные от процесса 3: общее время… 0.0035021 сек
Лабораторная работа № 5
Матричные вычисления
1. Подготовка к работе
Необходимо иметь в наличии работающий кластер на базе MPICH Уметь программировать на языке С. Ознакомится с методом решения СЛАУ методом решения Якоби.
Контрольные вопросы
1. Каким образом организуеия совместная работа всех процессов с одной матрицей.
2. Как происходит обработка матрицы несколькими процессами.
3. Что делает каждый процесс с общей матрицей при расчете.
4. Описишите принцип метода Якоби.
5. Что делает функция MPI_Allreduce()
6. С какой точностью производится расчет?
7. Что такое точечная посылка?
8. Чем отличается посылка с блокировкой от посылки без блокировки?
9. Как процесс получает именно свое сообщение?
10. Почему нужно использовать MPI_WTime для получения времени?
11. Из-за чего могут возникать задержки в передаче данных между процессами?
3. Задание
Для решения системы СЛАУ методом Якоби вам требуется решить уравнение Лапласа. Для это требуется создать матрицу и использовать данный алгоритм.
4. Методические указания
Каждый процесс создает матрицу разрера 12Х12 ячеек, которые будут обрабатываться четырьмя процессами. Исходная матрица разделяется на четыре части, каждая из них обрабатывается отдельным процессом, используя функцию:
for (i,j) xnew [i][ j] = (x[ i + 1][ j] + x[ i- I][j] + x[i][j + 1] + х [i][ j - 1]/4;
for(i,j) x [i][j ]= xnew [i][j].
Для этого нам потребуется каждому процессу иметь доступ к следующим элементам матрицы:
X [0 ][ j ], x[ n – 1] [j], x [ i ][ 0], x [i ] [n - 1].
Каждый процесс будет обрабатывать ¼ часть матрицы, деля ее по горизонтали. Затем результат работы четырех процессов суммируется нулевым процессом.
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3
2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
В данной примерной матрице номерами указан какую ячейку обрабатывает каждый процесс, где –1 суммируется нулевым процессом. Всего выполняется 100 итераций. Для сбора результатов от процессов используйте функцию MPI_Allreduce() с параметром MPI_SUM.
5.
|
6. Пример выполнения
At iteration 1, diff is 3. 791438e + 000
At iteration 2, diff is 3. 948557e + 000
At iteration 3, diff is 3. 324536e + 000
At iteration 4, diff is 3. 014272e + 000
At iteration 5, diff is 3. 266808e + 001
At iteration 6, diff is 3. 992270e + 001
At iteration 7, diff is 3. 063208e + 001
At iteration 8, diff is 3. 354581e + 001
At iteration 9, diff is 3. 796424e + 001
At iteration 10, diff is 3. 345620e + 001
. . .
At iteration 91, diff is 1. 077600e + 002
At iteration 92, diff is 1. 033949e + 002
At iteration 93, diff is 9. 920652e + 003
Final solution is
-1.00000 –1.00000 –1.00000 –1.00000 –1.00000 –1.00000 –1.00000 –1.00000 –1.00000
-1.00000 –1.00000 –1.00000
3.000000 0.892898 0.065635 -0.299648 -0.470180 -0.539828 -0.539828 -0.470180
0.892898 3.00000
3.000000 1.505402 0.668228 -0.043031 -0.151248 -0.043031 0.204468 0.668228
1.505402 3.000000
2.000000 1.459421 0.895371 0.489475 0.241411 0.125389 0.125386 0.241411 0.489475 0.895371 1.459421 2.000000
2.000000 1.435428 0.961518 0.612675 0.389030 0.280790 0.280790 0.389030 0.612675 0.961518 1.435428 2.000000
2.000000 1.318993 0.899183 0.605903 0.415499 0.321700 0.415499 0.605903 0.899183
1.318993 2.000000
1.0000000 0.939427 0.706611 0.491070 0.339122 0.262020 0.262020 0.33122 0.491070 0.706611 0.939427 1.000000
1.000000 0.730175 0.493062 0.307470 0.181674 0.118464 0.118464 0.181674
0.307470 0.493062 0.730175 1.000000
1.000000 0.486443 0.224600 0.059331 –0.044069 –0.094514 -0.094514 -0.044069 0.059331 0.224600 0.486443 1.000000
0.000000 -0.010469 -0.143252 -0.254610 -0.327503 -0.363090 -0.363090 -0.327503 -0.254610 -0.143252 -0.010469 0.000000
0.000000 –0.386115 -0.534537 -0.609828 -0.670933 –0.670933 -0.651626 -0.609828 -0.534537 -0.386115 0.000000
-1.000000 –1.000000 –1.000000 –1.000000 –1.000000 –1.000000 –1.000000 –1.000000 –1.000000 –1.000000 –1.000000 –1.000000
Приложение А
Основные понятия
Наиболее распространенной технологией программирования для параллельных компьютеров с распределенной памятью в настоящее время является 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, иначе код ошибки.
Приложение В
Краткий справочник функций MPI
Процедуры инициализации
Функция | Описание | Аргументы |
MPI_Init(*argc,*argv) | Процедура инициализации MPI интерфейса. Должна вызываться до первой любой MPI фунции | Аргументы, переданные программе при запуске |
MPI_Comm_size(comm,*size) | Получает число процессов в коммуникаторе | Номер коммуникатора, переменная для хранения результата |
MPI_Comm_rank(comm,*rank) | Получет номер процесса | Номер коммуникатора, переменная для хранения результата |
MPI_Abort(comm,errorcode) | Аварийный выход из MPI программы | Номер коммуникатора, номер ошибки при выходе |
MPI_Get_processor_name(*name,*resultlength) | Получить имя хоста | Буфер для хранения строки с именем, число символов в буфере |
MPI_Initialized (*flag) | Индикация прохождения инициализации MPI интерфейса | Флаг состояния (1-успешно, 0 –ошибка) |
MPI_Wtime () | Получить время в секундах, прошедшее с начала суток | |
MPI_Finalize () | Остановка MPI интерфейса и отчистка памяти программы. Должна вызыватся в любой MPI программе. После неё вызывать MPI функции нельзя (включая MPI_Init()) |
Сообщения «точка-точка»
Функция | Описание | Аргументы |
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_Sendrecv (*sendbuf,sendcount,sendtype,dest,sendtag, *recvbuf, recvcount, recvtype, source, recvtag, comm,*status) | Комбинированный вариант. Одновременная отсылка и получение информации. | Буфер отправляемой информации, количество отпр. Информации, тип отпр. Инф., получатель, таг отправителя, то же самое для получения. |
MPI_Probe (source,tag,comm,*status) | Проверка на блокировки. Возвращает состяние блокировок. | Получатель, таг, коммуникатор, статус |
Групповые сообщения
Функция | Описание | Аргументы |
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 (*sendbuf,*recvbuf,count,datatype,op,comm) | Выполняет групповую операцию над буфером и рассылает результаты всем процессам | Буфер, количество элементов в буфере, тип данных в буфере, операция, процесс отправитель, коммуникатор. |
Типы пересылаемых данных
Тип в MPI | Соответствующий тип в Си |
MPI_CHAR | signed char |
MPI_SHORT | signed short int |
MPI_INT | signed int |
MPI_LONG | signed long int |
MPI_UNSIGNED_CHAR | unsigned char |
MPI_UNSIGNED_SHORT | unsigned short |
MPI_UNSIGNED | unsigned int |
MPI_UNSIGNED_LONG | unsigned long int |
MPI_FLOAT | float |
MPI_DOUBLE | double |
MPI_LONG_DOUBLE | long double |
MPI_BYTE | 8 бит |
MPI_PACKED | Данные, упакованные с помощью MPI_Pack() |
Аргументы
Аргумент | Тип | Описание |
Буфер (buffer) | *char | Указатель на буфер, где хранятся пересылаемые данные. Должен выделяться до вызова функций с помощью malloc |
Количество( Count) | Unsigned long | Количество элементов в буфере. Например длина текстовой строки. |
Тип (type) | MPI_TYPE | Тип передаваемых данных. См. предыдущую таблицу |
Получатель (destination) | Unsigned long | Номер процесса-получателя. Если получатель не важен или нужен всем MPI_ANY_SOURCE |
Таг (tag) | Unsigned long | Идентификатор сообщения. Должен совпадать в функциях отправки и функции, которая получает отправленные данные. Если это не важно или не нужно – используется тег MPI_ANY_TAG |
Коммуникатор (comm) | Unsigned long | Номер коммуникатора. Если сообщение требуется разослать всем процессам – используется MPI_COMM_WORLD |
Статус (status) | Struct MPI_STATUS | Структура, содержащая статус выполненной функции. Формат можно посмотреть в файле mpi.h |
Запрос (request) | Struct MPI_REQUEST | Структура для асинхронных операций пересылки. С помощью неё можно в дальнейшем проверить состояние пересылаемого сообщения. |