Основи програмування в рамках стандарту mpi

3.2 Основи програмування в рамках стандарту MPI

Кожен процес паралельної програми породжується на основі копії одного і того ж програмного коду (модель SPMP - Single Programm Multiple Processes). Даний програмний код, представлений у вигляді програми, що виконується, повинен бути доступний в момент запуску паралельної програми на всіх використовуваних процесорах. Вихідний програмний код для виконуваної програми розробляється на алгоритмічних мовах C або Fortran з використанням тієї чи іншої реалізації бібліотеки MPI.

Кількість процесів і число використовуваних процесорів визначається в момент запуску паралельної програми засобами середовища виконання MPI-програм і в ході обчислень мінятися не може (в стандарті MPI-2 передбачається можливість динамічної зміни кількості процесів). Всі процеси програми послідовно пронумеровані від 0 до p-1, де p є загальна кількість процесів. Номер процесу іменується рангом процесу.

При цьому для того, щоб уникнути ідентичності обчислень на різних процесорах, можна, по-перше, підставляти різні дані для програми на різних процесорах, а по-друге, за допомогою засобів для ідентифікації процесу, на якому виконується програма і тим самим, надається можливість організувати відмінності в обчисленнях в залежності від використовуваного програмою процесора.

Це дозволяє завантажувати ту чи іншу підзадачу в залежності від "номери" процесора. При цьому вихідна завдання розбивається на підзадачі (декомпозиція). Звичайна техніка полягає в наступному: кожна з підзадач оформляється у вигляді окремої структурної одиниці (функції, модуля), на всіх процесорах запускається одна і та ж програма "завантажувач", яка, в залежності від "номери" процесора завантажує ту чи іншу підзадачу.

Наведемо мінімально необхідний набір функцій MPI, достатній для розробки порівняно простих паралельних програм.

Найпростіша MPI програма.

Розглянемо паралельний варіант прикладу широко використовується демонстраційної програми "Hello world". На додаток до звичайного повідомленням кожен процес буде друкувати свій номер і загальна кількість процесів.

# include
# Include "mpi. H"
int main (int argc. char * argv [])
<
int procs_rank. procs_count;
MPI_Init ( argc. argv);
// ініціалізація MPI-бібліотеки
MPI_Comm_size (MPI_COMM_WORLD. procs_count);
// визначаємо кількість процесів
MPI_Comm_rank (MPI_COMM_WORLD. procs_rank);
// дізнаємося ранг процесу
printf ( "\ n Hello. World from process% 3 d of% 3 d". procs_rank. procs_count);
MPI_Finalize ();
// закриваємо MPI-бібліотеки
return 0;
>

Розберемо детально приклад:

Спочатку підключається заголовки бібліотеки "mpi. H". що складається з визначень функцій, типів і констант MPI. Цей файл необхідно включати в усі модулі, що використовують MPI.

Першим в кожної MPI програмою повинен бути виклик MPI_Init. який повинен бути присутнім в кожній програмі MPI і передує всім іншим викликам MPI. Він встановлює "середовище" (environment) MPI. Тільки одне звернення до MPI_Init допускається у виконанні програми. Його аргументами є кількість аргументів командного рядка процесу і власне командний рядок процесу.

int MPI_Init (int * argc. char *** argv)

  • argc - покажчик на кількість параметрів командного рядка;
  • argv - параметри командного рядка.

Функція MPI_Comm_size повертає в procs_count число запущених для даної програми процесів. Яким способом користувач запускає ці процеси - залежить від реалізації, але будь-яка програма може визначити число запущених процесів з допомогою даного виклику. Значення procs_count - це, по суті, розмір групи, пов'язаної з комунікатором MPI_COMM_WORLD. Процеси кожної групи пронумеровані цілими числами, починаючи з 0. які називаються рангами (rank). Кожен процес визначає свій номер в групі, пов'язаної з даними комунікатором, за допомогою MPI_Comm_rank. Таким чином, кожен процес отримує одне і те ж число в procs_count. але різні числа в rank. Кожен процес друкує свій ранг і загальна кількість запущених процесів, потім всі процеси виконують MPI_Finalize. Ця функція повинна бути виконана кожним процесом MPI і призводить до ліквідації "середовища" MPI. Ніякі виклики MPI не можуть бути здійснені процесом після виклику MPI_Finalize (повторний MPI_Init також неможливий).

Функція визначення числа процесів в області зв'язку MPI_Comm_size.

int MPI_Comm_size (MPI_Comm comm. int * size)

де comm - комунікатор, size - число процесів в області зв'язку комунікатора comm.

Функція визначення номера процесу MPI_Comm_rank.

int MPI_Comm_rank (MPI_Comm comm. int * rank)

де comm - комунікатор, rank - номер процесу, визвавщего функцію.

Функція завершення MPI програм MPI_Finalize не має параметрів.

int MPI_Finalize (void)

Розглянемо результат роботи цієї програми для двох процесів.

2 варіанти виходить з-за того що черговість появи текстових повідомлень визначається тим, який із процесів раніше виконає оператор друку, що взагалі кажучи, складно передбачити заздалегідь. Одне з можливих рішень цієї проблеми, про яку піде мова пізніше, полягає в тому, щоб зібрати дані на одному з процесів і потім зробити їх висновок.

Визначення часу виконання MPI програми

Практично відразу ж після розробки перших паралельних програм виникає необхідність визначення часу виконання обчислень для оцінки досягається прискорення процесів вирішення завдань за рахунок використання паралелізму. Використовувані зазвичай засоби для вимірювання часу роботи програм залежать, як правило, від апаратної платформи, операційної системи, алгоритмічного мови і т.п. Стандарт MPI включає визначення спеціальних функцій для вимірювання часу, застосування яких дозволяє усунути залежність від середовища виконання паралельних програм. Отримання поточного моменту часу забезпечується за допомогою функції:

double MPI_Wtime (void);

результат її виклику є кількість секунд, що минув від деякого певного моменту часу в минулому. Цей момент часу в минулому, від якого відбувається відлік секунд, може залежати від середовища реалізації бібліотеки MPI, і, тим самим, для відходу від такої залежності функцію MPI_Wtime слід використовувати тільки для визначення тривалості виконання тих чи інших фрагментів коду паралельних програм. Можлива схема застосування функції MPI_Wtime може полягати в наступному:

<
double starttime. endtime;
starttime = MPI_Wtime ();
// Деякі операції
endtime = MPI_Wtime ();
printf ( "Work time% f sec \ n". endtime - starttime);
>

Точність вимірювання часу також може залежати від середовища виконання паралельної програми. Для визначення поточного значення точності може бути використана функція:

double MPI_Wtick (void);

що дозволяє визначити час в секундах між двома послідовними показниками часу апаратного таймера застосованої комп'ютерної системи.