Міністерство Освіти і Науки України
Національний Університет “Львівська Політехніка”
Кафедра ЕОМ
ОЗНАЙОМЛЕННЯ З ТЕХНОЛОГІЄЮ ПАРАЛЕЛЬНОГО ПРОГРАМУВАННЯ ЗАСОБАМИ МРІ
Методичні вказівкидо лабораторної роботи № 3 з курсу “Паралельні та розподілені обчислення”
для студентів базового напряму 6.0915 - “Комп’ютерна інженерія”
Затвердженона засіданні кафедри”Електронні обчислювальні машини”Протокол № _ від 2010 року
Львів – 2010
Ознайомлення з технологією паралельного програмування засобами МРІ: Методичні вказівки до лабораторної роботи № 3 з курсу “Паралельні та розподілені обчислення” для студентів базового напряму 6.0915 - “Комп’ютерна інженерія”/ Укладачі: Є. Ваврук, О. Акимишин – Львів: Національний університет “Львівська політехніка”, 2010, 14 с.
Укладачі: Є. Ваврук, к.т.н., доцент.
О. Акимишин, к.т.н., асистент
Відповідальний за випуск: Мельник А. О., професор, завідувач кафедри
Рецензенти: Попович Р.Б., к. т. н, доцент
Юрчак І.Ю., к. т. н, доцент
МЕТА РОБОТИ
Вивчити основні поняття та визначення МРІ. Набути навиків розробки паралельних програм з використанням MPI.
ТЕОРЕТИЧНІ ВІДОМОСТІ:
У обчислювальних системах з розподіленою пам'яттю процесори працюють незалежно один від одного. Для організації паралельних обчислень в таких умовах необхідно мати можливість розподіляти обчислювальне навантаження і організувати інформаційну взаємодію (передачу даних) між процесорами. Одним з способів взаємодії між паралельними процесами є передача повідомлень між ними, що відображено в самій назві технології МРІ (message passing interface) – інтерфейс передачі повідомлень.
Для розподілу обчислень між процесорами необхідно проаналізувати алгоритм розв’язку задачі, виділити інформаційно незалежні фрагменти обчислень, виконати їх програмну реалізацію і розмістити отримані частини програми на різних процесорах. В MPI використовуються простіший підхід - для виконання завдання розробляється одна програма, яка запускається одночасно на виконання на всіх наявних процесорах. При цьому для того, щоб уникнути ідентичності обчислень на різних процесорах, можна, по-перше, підставляти різні дані для програми на різних процесорах, а по-друге, використовувати наявні в MPI засоби для ідентифікації процесора, на якому виконується програма (тим самим надається можливість організувати відмінності в обчисленнях залежно від використовуваного програмою процесора).
Інтерфейс МРІ підтримує реалізацію програм для MIMD систем (Multiple Instructions Multiple Data), проте відлагодження таких програм є не тривіальною задачею. Тому на практиці для написання програм в більшості випадків застосовується SPMD (single program multiple processes) модель паралельного програмування - "одна програма безліч процесів".
1. MPI: основні поняття і визначення
MPI - це стандарт, якому повинні задовольняти засоби організації передачі повідомлень. Крім того MPI - це програмні засоби, які забезпечують можливість передачі повідомлень і при цьому відповідають всім вимогам стандарту MPI. Згідно стандарту, ці програмні засоби повинні бути організовані у вигляді бібліотек програмних функцій (бібліотеки MPI) і повинні бути доступні для найширше використовуваних алгоритмічних мов C і Fortran. Подібну "подвійність" MPI слід враховувати при використанні термінології. Як правило, абревіатура MPI застосовується при згадці стандарту, а поєднання "бібліотека MPI" указує на ту або іншу програмну реалізацію стандарту. Оскільки достатньо часто скорочено позначення MPI використовується і для бібліотек MPI, тому для правильної інтерпретації терміну, слід враховувати контекст.
1.1. Поняття паралельної програми. Під паралельною програмою в MPI розуміється множина одночасно виконуваних процесів. Процеси можуть виконуватися як на різних процесорах, так і на одному процесорі можуть виконуватися і декілька процесів (в цьому випадку їх виконання здійснюється в режимі розділення часу). У граничному випадку для виконання паралельної програми може використовуватися один процесор - як правило, такий спосіб застосовується для початкової перевірки правильності паралельної програми.
Кожен процес паралельної програми породжується на основі копії одного і того ж програмного коду (модель SPMP). Даний програмний код, представлений у вигляді виконуваної програми, повинен бути доступний у момент запуску паралельної програми на всіх використовуваних процесорах. Початковий програмний код для виконуваної програми розробляється на алгоритмічних мовах C або Fortran із застосуванням тієї або іншої реалізації бібліотеки MPI.
Кількість процесів і використовуваних процесорів визначається у момент запуску паралельної програми засобами середовища виконання MPI-програм і в ході обчислень не може змінюватися без застосування спеціальних засобів динамічного породження процесів і управління ними, згідно з стандартом MPI версії 2.0. Всі процеси програми послідовно перенумеровані від 0 до p-1, де p є загальна кількість процесів. Номер процесу іменується рангом процесу.
1.2. Операції передачі даних. Основу MPI складають операції передачі повідомлень. Серед передбачених у складі MPI функцій розрізняються парні (point-to-point) операції між двома процесами і колективні (collective) комунікаційні дії для одночасної взаємодії декількох процесів.
Для виконання парних операцій можуть використовуватися різні режими передачі (синхронний, блокуючий і ін.). Повний розгляд можливих режимів передачі розглядається нище.
1.3. Поняття комунікаторів. Процеси паралельної програми об'єднуються в групи. Іншим важливим поняттям MPI, що описує набір процесів, є поняття комунікатора. Під комунікатором в MPI розуміється спеціально створений службовий об'єкт, який об'єднує групу процесів і ряд додаткових параметрів (контекст), використовуваних при виконанні операцій передачі даних.
Парні операції передачі даних можуть бути виконані між будь-якими процесами одного і того ж комунікатора, а в колективних операціях беруть участь всі процеси комунікатора. Як результат, вказання використовуваного комунікатора є обов'язковим для операцій передачі даних в MPI.
Логічна топологія ліній зв'язку між процесами має структуру повного графа (незалежно від наявності реальних фізичних каналів зв'язку між процесорами).
У MPI є можливість представлення множини процесів у вигляді граток довільної розмірності. Крім того, в MPI є засоби і для формування логічних (віртуальних) топологій будь-якого необхідного типу.
Під час обчислень можуть створюватися нові і видалятися існуючі групи процесів і комунікаторів. Один і той же процес може належати різним групам і комунікаторам. Всі наявні в паралельній програмі процеси входять до складу конструйованого за замовчуванням комунікатора з ідентифікатором MPI_COMM_WORLD.
У версії 2.0 стандарту з'явилася можливість створювати глобальні комунікатори (intercommunicator), об'єднуючи в одну структуру пару груп при необхідності виконання колективних операцій між процесами з різних груп.
1.4. Типи даних. При виконанні операцій передачі повідомлень для вказівки передаваних або отримуваних даних у функціях MPI необхідно вказувати тип даних, що пересилаються. MPI містить великий набір базових типів даних, багато в чому співпадаючих з типами даних в алгоритмічних мовах C і Fortran. Крім того, в MPI є можливості створення нових похідних типів даних для точнішого і коротшого опису вмісту повідомлень, що пересилаються.
2. Введення в розробку паралельних програм з використанням MPI
Мінімально необхідний набір функцій MPI, достатній для розробки порівняно простих паралельних програм.
2.1. Ініціалізація і завершення MPI-програм. Першою функцією MPI, що викликається, повинна бути функція
int MPI_Init(int *argc, char ***argv), де
argc - вказівник на кількість параметрів командного рядка;
argv - параметри командного рядка.
яка використовується для ініціалізації середовища виконання MPI-програми. Параметрами функції є кількість аргументів в командному рядку і адреса вказівника на масив параметрів командного рядка.
Останньою функцією MPI, що викликається, обов'язково повинна бути функція:
int MPI_Finalize(void).
Структура паралельної програми з використанням MPI повинна мати такий вигляд:
#include "mpi.h"
int main(int argc, char *argv[])
{
<програмний код без використання функцій MPI>
MPI_Init(&argc, &argv);
<програмний код з використанням функцій MPI>
MPI_Finalize();
<програмний код без використання функцій MPI>
return 0;
}
Варто зазначити:
Файл mpi.h містить визначення іменованих констант, прототипів функцій і типів даних бібліотеки MPI.
Функції MPI_Init і MPI_Finalize є обов'язковими і повинні бути виконані (і лише один раз) кожним процесом паралельної програми.
Перед викликом MPI_Init може бути використана функція MPI_Initialized для визначення того, чи був раніше виконаний виклик MPI_Init, а після виклику MPI_Finalize - MPI_Finalized аналогічного призначення.
Розглянуті приклади функцій дають представлення синтаксису іменування функцій в MPI. Імені функції передує префікс MPI; далі одне або декілька слів назви; перше слово в імені функції починається із заголовного символу; слова розділяються знаком підкреслення. Назви функцій MPI, як правило, пояснюють призначення виконуваних функцією дій.
2.2. Визначення кількості і рангу процесів. Визначення кількості процесів у виконуваній паралельній програмі здійснюється за допомогою функції:
int MPI_Comm_size(MPI_Comm comm, int *size), де
comm - комунікатор, розмір якого визначається;
size - визначена кількість процесів в комунікаторі.
Для визначення рангу процесу використовується функція:
int MPI_Comm_Rank(MPI_Comm comm, int *rank), де
comm - комунікатор, в якому визначається ранг процесу;
rank - ранг процесу в комунікаторі.
Як правило, виклик функцій Mpi_comm_size і Mpi_comm_rank виконується відразу після Mpi_init для отримання загальної кількості процесів і рангу поточного процесу:
#include "mpi.h"
int main(int argc, char *argv[])
{
int ProcNum, ProcRank;
<програмний код без використання функцій MPI>
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &ProcNum);
MPI_Comm_rank(MPI_COMM_WORLD, &ProcRank);
<програмний код з використанням функцій MPI>
MPI_Finalize();
<програмний код без використання функцій MPI>
return 0;
}
Варто зазначити:
Комунікатор MPI_COMM_WORLD, як наголошувалося раніше, створюється за замовчуванням і представляє всі процеси виконуваної паралельної програми.
Ранг, що отримується за допомогою функції MPI_Comm_rank, є рангом процесу, що виконав виклик цієї функції, тобто змінна ProcRank прийме різні значення у різних процесів.
2.3. Передача повідомлень. Для передачі повідомлення процес-відправник повинен виконати функцію:
int MPI_Send(void *buf, int count, MPI_Datatype type, int dest, int tag, MPI_Comm comm), де
buf - адреса буфера пам'яті, в якому розташовуються дані повідомлення, що відправляється;
count - кількість елементів даних в повідомленні;
type - тип елементів даних повідомлення, що пересилається;
dest - ранг процесу, якому відправляється повідомлення;
tag - значення-тег, що використовується для ідентифікації повідомлення;
comm - комунікатор, в рамках якого виконується передача даних.
Для вказання типу даних, що пересилаються, в MPI є ряд базових типів, повний список яких наведений в таблиці
Базові типи даних MPI для алгоритмічної мови C
Тип даних MPI
Тип даних C
MPI_BYTE
MPI_CHAR
signed char
MPI_DOUBLE
Double
MPI_FLOAT
Float
MPI_INT
Int
MPI_LONG
Long
MPI_LONG_DOUBLE
long double
MPI_PACKED
MPI_SHORT
Short
MPI_UNSIGNED_CHAR
unsigned char
MPI_UNSIGNED
unsigned int
MPI_UNSIGNED_LONG
unsigned long
MPI_UNSIGNED_SHORT
unsigned short
Варто зазначити:
Повідомлення, що відправляється, визначається шляхом задання блоку пам'яті (буфера), в якому це повідомлення розташовується. Використовувана для цього тріада (buf, count, type) входить до складу параметрів практично всіх функцій передачі даних.
Процеси, між якими виконується передача даних обов'язково повинні належати комунікатору, що вказується у функції MPI_Send.
Параметр tag використовується тільки при необхідності розрізнення передаваних повідомлень, інакше, як значення параметра, може бути використане довільне додатнє ціле число.
Відразу після завершення виконання функції MPI_Send процес-відправник може почати повторно використовувати буфер пам'яті, в якому розташовувалося повідомлення, що відправлялося. Також необхідно пам’ятати, що у момент завершення функції MPI_Send стан самого повідомлення, що пересилається, може бути абсолютно різним: повідомлення може розташовуватися в процесі-відправнику, може знаходитися в стані передачі, може зберігатися в процесі-одержувачі або ж може бути прийнято процесом-одержувачем за допомогою функції MPI_Recv. Тим самим, завершення функції MPI_Send лише означає, що операція передачі почала виконуватися і пересилка повідомлення рано чи пізно буде виконана.
2.4. Прийом повідомлень. Для прийому повідомлення процес-одержувач повинен виконати функцію:
int MPI_Recv(void *buf, int count, MPI_Datatype type, int source,
int tag, MPI_Comm comm, MPI_Status *status), де
buf, count, type - буфер пам'яті для прийому повідомлення, призначення кожного окремого параметра відповідає опису в MPI_Send.
source - ранг процесу, від якого повинен бути виконаний прийом повідомлення.
tag - тег повідомлення, яке повинне бути прийняте для процесу.
comm - комунікатор, в рамках якого виконується передача даних.
status - вказівник на структуру даних з інформацією про результат виконання операції прийому даних.
Варто зазначити:
Буфер пам'яті повинен бути достатнім для прийому повідомлення. При браку обсягу пам'яті частина повідомлення буде втрачена і в коді завершення функції буде зафіксована помилка переповнення. З іншого боку, повідомлення, що приймається, може бути коротшим від розміру приймального буфера. У такому разі зміняться тільки області буфера, використані прийнятим повідомленням.
Типи елементів повідомлення, що передаються і приймаються, повинні співпадати.
При необхідності прийому повідомлення від будь-якого процесу-відправника для параметра source може бути вказане значення MPI_ANY_SOURCE (на відміну від функції передачі MPI_Send, яка посилає повідомлення строго певного адресата).
При необхідності прийому повідомлення з будь-яким тегом для параметра tag може бути вказане значення MPI_ANY_TAG (знову-таки, при використанні функції MPI_Send повинне бути вказане конкретне значення тега).
На відміну від параметрів "процес-одержувач" і "тег", параметр "комунікатор" не має значення, що означає "будь-який комунікатор".
Параметр status дозволяє визначити ряд характеристик прийнятого повідомлення.
Status.MPI_SOURCE - ранг процесу - відправника прийнятого повідомлення.
Status.MPI_TAG - тег прийнятого повідомлення.
Значення змінної status дозволяє визначити кількість елементів даних в прийнятому повідомленні за допомогою функції:
int MPI_Get_count(MPI_Status *status, MPI_Datatype type, int *count), де
status - статус операції MPI_Recv;
type - тип прийнятих даних;
count - кількість елементів даних в повідомленні.
Виклик функції Mpi_Recv не зобов'язаний бути узгодженим з часом виклику відповідної функції передачі повідомлення MPI_Send - прийом повідомлення може бути ініційований до моменту, в момент чи після моменту початку відправки повідомлення.
Після закінчення виконання функції MPI_Recv в заданому буфері пам'яті буде розташоване прийняте повідомлення. Принциповий момент полягає в тому, що функція MPI_Recv є блокуючою для процесу-одержувача, тобто його виконання припиняється до завершення роботи функції. Таким чином, якщо, по якихось причинах очікуване для прийому повідомлення буде відсутнє, виконання паралельної програми буде блоковано.
3. Інсталяція та зв’язування бібліотеки MPI
3.1. Встановлення бібліотеки.
Запускаємо файл mpich2-1.0.8-win-ia32.msi
Натискаємо кнопку Next Натискаємо кнопку Next
Погоджуємось з ліцензійними вимогами і натискаємо кнопку Next. Вибираємо директорію в якій буде розміщуватись MPI і натискаємо кнопку Next
Чекаємо завершення встановлення та натискаємо кнопку Сlose
3.2. Командою net user username password /add прописати обліковий запис, під яким запускатимуться MPI- програми
3.3. Додати до середовища Visual Studio шляхи розміщення заголовних файлів та бібліотек
Після виконаних вказаних кроків бібліотека MPI готова до використання.
КОНТРОЛЬНІ ЗАПИТАННЯ
Яка модель організації обчислень застосовується для написання програм з використанням МРІ?
Пояснити поняття паралельної програми в МРІ.
Навести структуру паралельної програми з використанням МРІ?
Як визначити кількість процесів у виконуванній паралельній програмі?
Які типи обміну повідомлень між процесами ви знаєте?
ПОРЯДОК ВИКОНАННЯ РОБОТИ
Встановити та налаштувати бібліотеку МРІ для розробки програм у середовищі програмування Microsoft Visual Studio 2005.
Написати програму обміну повідомлень між процесами з використанням МРІ. Кожен процес має визначати свій ранг та пересилати його значення головному процесу. Головний процес повинен виводити отримане значення на екран.
Виконати розроблену програму для різної кількості процесів.
Зробити висновок про порядок прийому повідомлень головним процесом та звернути увагу на його зміну від виклику до виклику розробленої програми.
ЗМІСТ ЗВІТУ ДО ЛАБОРАТОРНОЇ РОБОТИ
1. Структура паралельної програми з використанням МРІ.
2. Завдання (кількість процесів) згідно варіанту.
3. Текст програми на С з використанням бібліотеки МРІ.
4. Вікно консолі з результатами виконання програми (результат друку рангів процесів).
5. Висновок.
ЗАВДАННЯ
Варіант №
Кількість процесів 1
Кількість процесів 2
1
4
26
2
8
22
3
3
27
4
7
23
5
5
25
6
2
28
7
6
24
8
12
18
9
10
22
10
30
10
11
15
5
12
22
8
13
11
19
14
13
17
15
16
14
16
9
21
17
18
12
18
23
7
19
25
5
20
27
3
21
14
16
22
19
11
23
6
24
24
8
22
25
11
19
26
14
18
27
16
22
28
18
8
29
8
12
30
6
22
ЛІТЕРАТУРА
А. А. Букатов, В. Н. Дацюк, А. И. Жегуло. Программирование многопроцессорных вычислительных систем. Ростов-на-Дону. Издательство ООО «ЦВВР», 2003, 208 с.
Антонов А.С. Параллельное программирование с использованием технологии МРІ: Учебное пособие. – М.: Издательство МГУ, 2004. – 71 с.
Є. Ваврук, О. Лашко. Організація паралельних обчислень: Навчальний посібник. – Львів: Національний університет “Львівська політехніка”, 2007. – 70 с.
www.parallel.ru
www.mcs.anl.gov/mpi/mpich
ПРИКЛАД ВИКОНАННЯ
Завдання:
Написати програму обміну повідомленнями між процесами з використанням МРІ та запустити її для 4 процесів.
Текст програми:
#include <stdio.h>
#include "mpi.h"
int main(int argc, char* argv[])
{
int ProcNum, ProcRank, RecvRank;
MPI_Status Status;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &ProcNum);
MPI_Comm_rank(MPI_COMM_WORLD, &ProcRank);
if ( ProcRank == 0 )
{
// Дії виконуються тільки процесом з рангом 0
printf("\n Hello from process %3d", ProcRank);
for (int i = 1; i < ProcNum; i++ )
{
MPI_Recv(&RecvRank,1, MPI_INT, MPI_ANY_SOURCE,
MPI_ANY_TAG, MPI_COMM_WORLD, &Status);
printf("\n Hello from process %3d", RecvRank);
}
}
else // Повідомлення відправляється всіма процесами,
// крім процесу з рангом 0
MPI_Send(&ProcRank,1,MPI_INT,0,0,MPI_COMM_WORLD);
MPI_Finalize();
return 0;
}
Висновок
Порядок прийому повідомлень заздалегідь не визначений і залежить від умов виконання паралельної програми (більш того, цей порядок може змінюватися від запуску до запуску). Так, можливий варіант результатів друку процесу 0 для паралельної програми з чотирьох процесів наведено на рисунку вище.
НАВЧАЛЬНЕ ВИДАННЯ
ОЗНАЙОМЛЕННЯ З ТЕХНОЛОГІЄЮ ПАРАЛЕЛЬНОГО ПРОГРАМУВАННЯ ЗАСОБАМИ МРІ
МЕТОДИЧНІ ВКАЗІВКИ
до лабораторної роботи № 3 з дисципліни “Паралельні та розподілені обчислення”
для студентів для студентів базового напряму 6.0915 - “Комп’ютерна інженерія”
Укладачі: Ваврук Євгеній Ярославович
Акимишин Орест Ігорович
Редактор
Комп’ютерне верстання
Здано у видавництво . Підписано до друку
Формат 70х100/16. Папір офсетний. Друк на різографі
Умовн. друк. арк. Обл..-вид. арк..
Тираж прим. Зам..
Видавництво Національного університету “Львівська політехніка”
Реєстраційне свідоцтво ДК №751 від 27.12.2001 р.
Поліграфічний центр Видавництва
Національного університету “Львівська політехніка”
Вул.. Ф. Колесси, 2. Львів, 79000