Message Passing Interface

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

MPI (англ. Message Passing Interface, Інтерфейс передачі повідомлень) — це специфікація, що була розроблена в 1993–1994 роках групою MPI Forum[1],і забезпечує реалізацію моделі обміну повідомленнями між процесами. Остання версія цієї специфікації: MPI-2. У моделі програмування MPI програма породжує кілька процесів, що взаємодіють між собою за допомогою виклику підпрограм прийому й передачі повідомлень.

Зазвичай, при ініціалізації MPI-програми створюється фіксований набір процесів, причому (що, утім, необов'язково) кожний з них виконується на своєму процесорі. У цих процесах можуть виконуватися різні програми, тому MPI-модель іноді називають MIMD-моделлю (Multiple Instruction, Multiple Data), на відміну від SIMD моделі, де на кожному процесорі виконуються тільки однакові задачі. MPI підтримує двохточкові й глобальні, синхронні й асинхронні, блокуючі й неблокуючі типи комунікацій. Спеціальний механізм — комунікатор — ховає від програміста внутрішні комунікаційні структури. Структура комунікацій може змінюватися протягом часу життя процесу, але кількість задач має залишатися постійною (MPI-2 підтримує динамічну зміну кількості задач).

Специфікація MPI забезпечує переносимість програм на рівні вихідних кодів. Підтримується робота на гетерогенних кластерах і симетричних мультипроцесорних системах. Не підтримується запуск процесів під час виконання MPI-програми. У специфікації відсутні опис паралельного вводу-виводу й налагодження програм — ці можливості можуть бути включені до складу конкретної реалізації MPI у вигляді додаткових пакетів чи утиліт. Сумісність різних реалізацій не гарантується.

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

MPI-програма[ред. | ред. код]

#include <mpi.h> // очевидно;)
#include <stdio.h>

int main(int argc, char* argv[])
{
   int myrank, size;
   MPI_Init(&argc, &argv); // Ініціалізація MPI
   MPI_Comm_size(MPI_COMM_WORLD, &size); // Розмір комунікатора
   MPI_Comm_rank(MPI_COMM_WORLD, &myrank); // Одержуємо наш номер
   printf("Proc %d of %d\n", myrank, size);
   MPI_Finalize(); // Фіналізація MPI
   puts("Done.");
   return 0;
}

Перед викликом будь-якої процедури MPI, потрібно викликати ініціалізацію MPI_Init, перед цим викликом може здійснюватися тільки виклик MPI_Initialized. MPI_Init крім усього іншого створює глобальний комунікатор MPI_COMM_WORLD, через котрий буде проходити обмін повідомленнями. Область взаємодії комунікатора MPI_COMM_WORLD — усі процеси даної програми. Якщо є необхідність у розбивці області взаємодії на дрібніші сегменти (частково-широкомовні розсилання), використовуються виклики MPI_Comm_dup/create/split/etc (тут не розглядаються). Розмір комунікатора, одержуваний викликом MPI_Comm_size — число процесів у ньому. Розмір комунікатора MPI_COMM_WORLD — загальне число процесів. Кожен процес має свій унікальний (у межах комунікатора) номер — ранг. Ранги процесів у контекстах різних комунікаторів можуть відрізнятися. Після виконання всіх обмінів повідомленнями в програмі має здійснюватися виклик MPI_Finalize() — процедура видаляє всі структури даних MPI і робить інші необхідні дії. Програміст має сам подбати про те, щоб до моменту виклику MPI_Finalize усі пересилання даних було завершено. Після виконання MPI_Finalize виклик будь-яких, крім MPI_Initialized, процедур (навіть MPI_Init) неможливий. Програма виводить повідомлення від усіх породжених нею процесів. Приклад виводу (порядок повідомлень, що надходять від процесів, може змінюватися) наведений нижче (np — кількість процесів):

  Proc 1 of 3
  Done.
  Proc 0 of 3
  Done.
  Proc 2 of 3
  Done.

Зверніть увагу, що після виклику MPI_Finalize() парелельна робота не закінчується — «Done» виводиться кожним процесом.

Термінологія і позначення[ред. | ред. код]

  • Номер процесу — ціле невід'ємне число, що є унікальним атрибутом кожного процесу.
  • Атрибути повідомлення — номер процесу-відправника, номер процесу-одержувача і ідентифікатор повідомлення. Для них заведена структура MPI_Status, що містить три поля: MPI_Source (номер процесу відправника), MPI_Tag (ідентифікатор повідомлення), MPI_Error (код помилки); можуть бути і додаткові поля.
  • Ідентифікатор повідомлення (msgtag) — атрибут повідомлення, що є цілим невід'ємним числом у діапазоні від 0 до 32767.

Процеси об'єднуються в групи, можуть бути вкладені групи. Усередині групи всі процеси перенумеровані. З кожною групою асоційований свій комунікатор. Тому при здійсненні пересилання необхідно вказати ідентифікатор групи, всередині якої проводиться ця пересилка. Всі процеси містяться в групі з наперед визначеним ідентифікатором MPI_COMM_WORLD .

Стандарти MPI[ред. | ред. код]

Перша версія MPI розроблялася в 1993–1994 році, і MPI 1 вийшла в 1994. Більшість сучасних реалізацій MPI підтримують версію 1.1. Стандарт MPI версії 2.0 підтримується більшістю сучасних реалізацій, але деякі функції можуть бути реалізовані не до кінця. У MPI 1.1 (опублікований 12 червня 1995 , перша реалізація з'явилася в 2002 році) підтримуються наступні функції:

  • передача і отримання повідомлень між окремими процесами;
  • колективні взаємодії процесів;
  • взаємодії в групах процесів;
  • реалізація топологій процесів;

У MPI 2.0 (опублікований 18 липня 1997) додатково підтримуються наступні функції:

  • динамічне породження процесів і управління процесами;
  • односторонні комунікації (Get / Put);
  • паралельний введення і виведення;
  • розширені колективні операції (процеси можуть виконувати колективні операції не тільки всередині одного комунікатора, але й у рамках декількох комунікаторів).

Версія MPI 2.1 вийшла на початку вересня 2008 року. Версія MPI 2.2 вийшла 4 вересня 2009. Версія MPI 3.0 вийшла 21 вересня 2012 року.

Функціонування інтерфейсу[ред. | ред. код]

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

  • відправник — ранг (номер у групі) відправника повідомлення;
  • одержувач — ранг одержувача;
  • ознака — може використовуватися для розділення різних видів повідомлень;
  • комунікатор — код групи процесів.

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

Іншим способом зв'язку є віддалений доступ до пам'яті (RMA), що дозволяє читати і змінювати область пам'яті віддаленого процесу. Локальний процес може переносити область пам'яті віддаленого процесу (всередині зазначеного процесами вікна) в свою пам'ять і назад, а також комбінувати дані, передані у віддалений процес, з наявними в його пам'яті даними (наприклад, шляхом підсумовування). Всі операції віддаленого доступу до пам'яті не блокуються, однак, до і після їх виконання необхідно викликати блокуючі функції синхронізації.

Реалізації MPI[ред. | ред. код]

  • MPICH — найпоширеніша безкоштовна реалізація, працює на UNIX -системи і Windows NT
  • LAM / MPI — ще одна безкоштовна реалізація MPI. Підтримує гетерогенні конфігурації, LAM підтримує гетерогенні конфігурації, пакет Globus і задовольняє IMPI (Interoperable MPI).
  • WMPI — реалізація MPI для Windows
  • MPI / PRO For Windows NT — комерційна реалізація для Windows NT
  • Intel MPI — комерційна реалізація для Windows / Linux
  • Microsoft MPI входить до складу Compute Cluster Pack SDK . Заснований на MPICH2, але включає додаткові засоби управління завданнями. Підтримується специфікація MPI-2.
  • HP-MPI — комерційна реалізація від HP
  • SGI MPT — платна бібліотека MPI від SGI
  • Mvapich — безкоштовна реалізація MPI для Infiniband
  • Open MPI — безкоштовна реалізація MPI, спадкоємець LAM / MPI
  • Oracle HPC ClusterTools — безкоштовна реалізація для Solaris SPARC / x86 і Linux на основі Open MPI
  • MPJ — MPI for Java
  • MPJ Express — MPI на Java

Загальні процедури MPI[ред. | ред. код]

int MPI_Init (INT * ARGC, char *** ARGV)

MPI_Init — ініціалізація паралельної частини програми. Реальна ініціалізація для кожного додатка виконується не більше одного разу, а якщо MPI вже був ініціалізований, то ніякі дії не виконуються і відбувається негайне повернення з підпрограми. Всі інші MPI-процедури можуть бути викликані тільки після виклику MPI_Init .

Повертає: у разі успішного виконання — MPI_SUCCESS, інакше — код помилки. (Те ж саме повертають і всі інші функції MPI_*, вказані нижче)

int MPI_Finalize (void)

MPI_Finalize — завершення паралельної частини програми. Всі наступні звернення до будь-яких MPI-процедур (зокрема — до MPI_Init) заборонено. До моменту виклику якимось процесом MPI_Finalize має бути завершено всі дії, що вимагають його участі в обміні повідомленнями.

int MPI_Comm_size(MPI_Comm comm, int* size)

Показує розмір (кількість паралельних процесів) групи, асоційованої з комунікатором

  • comm — комунікатор (ідентифікатор групи)
  • int size — розмір групи

Прийом / передача повідомлень між окремими процесами[ред. | ред. код]

Прийом / передача повідомлень з блокуванням[ред. | ред. код]

int MPI_Send(void* buf, int count, MPI_Datatype datatype, int dest, int msgtag, MPI_Comm comm)

  • buf — адреса початку буфера посилки повідомлення
  • count — число переданих елементів у повідомленні
  • datatype — тип переданих елементів
  • dest — номер процесу-одержувача
  • msgtag — ідентифікатор повідомлення
  • comm — ідентифікатор групи

Блокуюче надсилання повідомлення з ідентифікатором msgtag, що складається з count елементів типу datatype, процесу з номером dest . Всі елементи повідомлення розташовані поспіль в буфері buf . Значення count може бути нулем. Тип переданих елементів datatype повинен вказуватися за допомогою зумовлених констант типу. Дозволяється передавати повідомлення самому собі.

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

Прийом / передача повідомлень без блокування[ред. | ред. код]

int MPI_Isend(void *buf, int count, MPI_Datatype datatype, int dest, int msgtag, MPI_Comm comm, MPI_Request *request)

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

Повідомлення, відправлене будь-якою з процедур MPI_Send і MPI_Isend, може бути прийняте будь-якою з процедур MPI_Recv і MPI_Irecv

Синхронізація процесів[ред. | ред. код]

int MPI_Barrier (MPI_Comm comm)

  • comm — ідентифікатор групи

Блокує роботу процесів, що викликали дану процедуру, доки всі інші процеси групи comm також не виконають цю процедуру.

Визначені константи[ред. | ред. код]

Константи MPI Тип в C
MPI_CHAR signed char
MPI_SHORT signed int
MPI_INT signed int
MPI_LONG signed long int
MPI_UNSIGNED_CHAR unsigned char
MPI_UNSIGNED_SHORT unsigned int
MPI_UNSIGNED unsigned int
MPI_FLOAT float

Див. також[ред. | ред. код]

Примітки[ред. | ред. код]

  1. Архівована копія. Архів оригіналу за 5 травня 2021. Процитовано 6 квітня 2010. 

Посилання[ред. | ред. код]