Message Passing Interface

**MPI** (, інтэрфэйс перадачы паведамленьняў) — спэцыфікацыя, распрацаваная ў 1993—1994 гадах групай MPI Forum , якая забясьпечвае рэалізацыю мадэлі абмену паведамленьнямі паміж працэсамі. Апошняя вэрсія згаданай спэцыфікацыі: MPI-2. У мадэлі праграмаваньня MPI праграма спараджае некалькі працэсаў, якія ўзаемадзейнічаюць паміж сабой з дапамогай звароту да падпраграмаў прыёму і перадачы паведамленьняў.

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

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

Важнай уласьцівасьцю паралельнай праграмы зьяўляецца дэтэрмінізм — праграма павінная заўсёды даваць той жа вынік для таго ж набору ўваходных дадзеных. Мадэль перадачы паведамленьняў такой здольнасьцю не валодае, паколькі ня вызначаны парадак атрыманьня паведамленьняў ад двух працэсаў трэцім. Калі ж адзін працэс пасьлядоўна пасылае некалькі паведамленьняў іншаму працэсу, MPI гарантуе, што атрымальнік атрымае іх менавіта ў тым парадку, у якім яны былі адпраўленыя. Адказнасьць за забесьпячэньне дэтэрмінаванага выкананьня праграмы кладзецца на праграміста.

## MPI-праграма


```c
# 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, працэдураў немагчымы. Праграма выводзіць паведамленьне ад усіх спароджаных ёю працэсаў. Прыклад вываду прыведзены ніжэй (**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. Падтрымлівае гетэрагенныя канфігурацыі.
* 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.

### Прыём / перадача паведамленняў без блакавання

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 Forum and MPI specification
* Platform MPI
* Open MPI web site
* LAM/MPI web site
* MPICH
* SCore MPI
* Parawiki page for MPI
* PVM/MPI Users' Group Meeting (2006 edition)
* Дакумэнтацыя па MPI: Tutorial, MPI Samples, Supercomputing Simplified, MPI Tutorial

Катэгорыя:Паралельныя вылічэньні