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