Výměna dat pomocí MPI. Práce s knihovnou MPI na příkladu knihovny Intel® MPI Library. Spuštění a zastavení programu MPI

Spuštění aplikace MPI na výpočetním clusteru je možné pouze prostřednictvím systému pro dávkové zpracování úloh. Pro zjednodušení spouštění a řazení paralelního programu je k dispozici speciální skript mpirun. Například mpirun -np 20 ./first.exe spustí paralelní program first.exe na 20 procesorech, tzn. na 5 uzlech. (Každý uzel má 2 dvoujádrové procesory). Stojí za zmínku, že ke spuštění spustitelného modulu umístěného v aktuálním adresáři ($pwd) musíte explicitně zadat cestu „./“. Řada implementací MPI-1 poskytuje příkaz ke spuštění pro programy MPI, který má tvar mpirun<аргументы mpirun><программа><аргументы программы>

Oddělení příkazu ke spuštění programu od samotného programu poskytuje flexibilitu, zejména pro síťové a heterogenní implementace. Standardní spouštěcí mechanismus také rozšiřuje přenositelnost programů MPI o krok dále na příkazové řádky a skripty, které s nimi manipulují. Například skript pro sadu ověřovacích programů, které spouštějí stovky programů, může být přenosný skript, pokud je napsán pomocí takového standardního spouštěcího mechanismu. Aby nedošlo k záměně ,,standardního'' příkazu se stávajícím v praxi, který není standardní a není přenosný mezi implementacemi, MPI definovalo mpiexec místo mpirun.

I když standardizovaný spouštěcí mechanismus zlepšuje použitelnost MPI, škála prostředí je tak rozmanitá (například nemusí existovat ani rozhraní příkazového řádku), že MPI nemůže takový mechanismus nařídit. Místo toho MPI definuje příkaz mpiexec run a doporučuje, ale nevyžaduje, jako radu pro vývojáře. Pokud však implementace poskytuje příkaz s názvem mpiexec, musí mít formu popsanou níže: mpiexec -n <программа>

bude alespoň jeden způsob, jak utéct<программу>s počátečním MPI_COMM_WORLD, jehož skupina obsahuje procesy. Další argumenty pro mpiexec mohou záviset na implementaci.

Příklad 4.1 Spuštění 16 instancí myprog na aktuálním nebo výchozím počítači:

mpiexec -n 16 myprog

3. Napište program pro paralelní výpočet určitého integrálu funkce 2*(x+2*x*x/1200.0) v intervalu .

Metoda levého obdélníku

dvojité f (dvojité x)

(návrat 2*(x+2*x*x/1200);) // integrál iskomyi

int main(int argc,char **argv)

stav MPI_Status;

MPI_Init(&argc,&argv);

MPI_Comm_rank(MPI_COMM_WORLD,&rank);

MPI_Comm_size(MPI_COMM_WORLD,&velikost);

int n=1000,i,d; // 1000 - uzly

float a=0, b=1, h=(b-a)/n,s=0,r=0; //a i b -nachalo i konec otřezka

if (rank!=size-1) // schitaut vse processy, krome poslednego

( pro (i=hodnost*d; i<(rank+1)*d; i++) { s=s+h*f(a+i*h); }

MPI_Send(&s,1,MPI_FLOAT,velikost-1,1,MPI_COMM_WORLD);)

(pro (i=0; i

( MPI_Recv(&s,1,MPI_FLOAT,i,1,MPI_COMM_WORLD, &status); r+=s; ) )

MPI_Finalize();)

Surak

1. Architektury sdílené a distribuované paměti.

Distribuovaná sdílená paměť (DSM – Distributed Shared Memory)

Tradičně je distribuovaný výpočet založen na modelu předávání zpráv, ve kterém jsou data předávána od procesoru k procesoru ve formě zpráv. Vzdálená volání procedur jsou ve skutečnosti stejným modelem (nebo velmi blízko). DSM je virtuální adresní prostor sdílený všemi uzly (procesory) distribuovaného systému. Programy přistupují k datům v systému DSM v podstatě stejným způsobem, jako přistupují k datům ve virtuální paměti tradičních počítačů. V systémech s DSM se data přesouvají mezi lokálními paměťmi různých počítačů stejným způsobem, jako se přesouvají mezi RAM a externí pamětí jednoho počítače. Konfigurace distribuované sdílené paměti je variantou distribuované paměti. Zde všechny uzly, sestávající z jednoho nebo více procesorů propojených prostřednictvím schématu SMP, využívají společný adresní prostor. Rozdíl mezi touto konfigurací a strojem s distribuovanou pamětí je v tom, že zde může jakýkoli procesor přistupovat k jakékoli části paměti. Doba přístupu pro různé části paměti se však u každého procesoru liší v závislosti na tom, kde se tato část v clusteru fyzicky nachází. Z tohoto důvodu se takové konfigurace také nazývají stroje s nejednotným přístupem do paměti (NUMA).

Rozdíly mezi MPI a PVM.

Systém PVM (Parallel Virtual Machine) byl vytvořen pro spojení několika síťových pracovních stanic do jednoho virtuálního paralelního výpočetního stroje. Systém je doplňkem operačního systému UNIX a používá se na různých hardwarových platformách, včetně masivně paralelních systémů. Nejběžnější paralelní programovací systémy jsou dnes založeny na MPI (Message Parsing Interface). Myšlenka MPI je zpočátku jednoduchá a zřejmá. Zahrnuje reprezentaci paralelního programu jako množiny paralelních prováděcích procesů, které se vzájemně ovlivňují během provádění přenosu dat pomocí komunikačních procedur. Tvoří knihovnu MPI. Správná implementace MPI pro podporu meziprocesorové komunikace se však ukázala jako poměrně obtížná. Tato složitost je spojena s potřebou dosáhnout vysokého výkonu programu, s nutností používat četné vícepočítačové zdroje a v důsledku toho s velkou rozmanitostí v implementaci komunikačních procedur v závislosti na režimu zpracování dat.

Anotace: Přednáška je věnována zvažování technologie MPI jako paralelního programovacího standardu pro distribuované paměťové systémy. Jsou zvažovány hlavní způsoby přenosu dat. Jsou představeny pojmy jako skupiny procesů a komunikátoři. Pokrývá základní datové typy, operace point-to-point, hromadné operace, synchronizační operace a měření času.

Účel přednášky: Přednáška je zaměřena na prostudování obecné metodologie pro vývoj paralelních algoritmů.

Videozáznam přednášky - (svazek - 134 MB).

5.1. MPI: základní pojmy a definice

Podívejme se na řadu pojmů a definic, které jsou pro standard MPI zásadní.

5.1.1. Koncept paralelního programu

Pod paralelní program v rámci MPI rozumíme soubor současně prováděných procesy. Procesy mohou být spouštěny na různých procesorech, ale na stejném procesoru může být umístěno i několik procesů (v tomto případě jsou vykonávány v režimu sdílení času). V krajním případě lze pro provedení paralelního programu použít jeden procesor - zpravidla se tato metoda používá k prvotní kontrole správnosti paralelního programu.

Každý proces paralelního programu je vytvořen z kopie stejného programového kódu ( Model SPMP). Tento programový kód, prezentovaný ve formě spustitelného programu, musí být dostupný v době spuštění paralelního programu na všech použitých procesorech. Zdrojový kód pro spustitelný program je vyvíjen v algoritmických jazycích C nebo Fortran s použitím jedné nebo druhé implementace knihovny MPI.

Počet procesů a počet použitých procesorů je určen v okamžiku spouštění paralelního programu pomocí prostředí pro provádění programu MPI a nemůže se během výpočtů měnit (standard MPI-2 počítá s možností dynamicky měnit počet procesů). Všechny procesy programu jsou postupně číslovány od 0 do p-1, Kde p je celkový počet procesů. Vyvolá se číslo procesu hodnost proces.

5.1.2. Operace přenosu dat

MPI je založeno na operacích předávání zpráv. Mezi funkcemi poskytovanými jako součást MPI jsou různé čtyřhra (point-to-point) operace mezi dvěma procesy a kolektivní (kolektivní) komunikační akce pro současnou interakci několika procesů.

K provádění spárovaných operací lze použít různé režimy přenosu, včetně synchronního, blokovacího atd. - plné zvážení možných přenosové režimy bude provedeno v pododdílu 5.3.

Jak již bylo uvedeno výše, standard MPI počítá s nutností implementace většiny základních operací hromadného přenosu dat – viz podkapitoly 5.2 a 5.4.

5.1.3. Koncepce komunikátorů

Procesy paralelního programu jsou kombinovány do skupiny. Pod komunikátor MPI označuje speciálně vytvořený objekt služby, který kombinuje skupinu procesů a řadu dalších parametrů ( kontext) používané při provádění operací přenosu dat.

Obvykle se operace párového přenosu dat provádějí pro procesy patřící stejnému komunikátoru. Kolektivní operace jsou aplikovány současně na všechny procesy komunikátoru. V důsledku toho je určení komunikátoru, který se má použít, pro operace přenosu dat v MPI povinné.

Během výpočtů lze vytvářet nové skupiny procesů a komunikátory a mazat stávající skupiny procesů a komunikátorů. Stejný proces může patřit k různým skupinám a komunikátorům. Všechny procesy přítomné v paralelním programu jsou obsaženy v komunikátoru vytvořeném standardně s identifikátorem MPI_COMM_WORLD.

Pokud je potřeba přenášet data mezi procesy z různých skupin, je nutné vytvořit globální komunikátor ( interkomunikátor).

Podrobná diskuse o možnostech MPI pro práci se skupinami a komunikátory bude provedena v pododdíle 5.6.

5.1.4. Typy dat

Při provádění operací předávání zpráv musíte zadat data, která mají být odeslána nebo přijata ve funkcích MPI. typ odeslaná data. MPI obsahuje velkou sadu základní typy data, která se do značné míry shodují s datovými typy v algoritmických jazycích C a Fortran. Kromě toho má MPI schopnost vytvářet nové odvozené typyúdaje pro přesnější a výstižnější popis obsahu přeposílaných zpráv.

Podrobná diskuse o možnostech MPI pro práci s odvozenými datovými typy bude provedena v podkapitole 5.5.

5.1.5. Virtuální topologie

Jak bylo uvedeno výše, operace párového přenosu dat lze provádět mezi libovolnými procesy stejného komunikátoru a všechny procesy komunikátoru se účastní společné operace. V tomto ohledu má logická topologie komunikačních linek mezi procesy strukturu úplného grafu (bez ohledu na přítomnost skutečných fyzických komunikačních kanálů mezi procesory).

Současně (a to již bylo uvedeno v části 3) je pro prezentaci a následnou analýzu řady paralelních algoritmů vhodné mít logickou reprezentaci stávající komunikační sítě ve formě určitých topologií.

MPI má schopnost reprezentovat více procesů ve formuláři mřížky libovolný rozměr (viz pododdíl 5.7). V tomto případě lze okrajové procesy mříží prohlásit za sousední a tím na základě mříží struktury typu torus.

Kromě toho má MPI nástroje pro generování logických (virtuálních) topologií libovolného požadovaného typu. Podrobná diskuse o možnostech MPI pro práci s topologiemi bude provedena v podkapitole 5.7.

A nakonec jedna poslední sada poznámek, než se začneme zabývat MPI:

  • Popisy funkcí a všechny příklady poskytovaných programů budou prezentovány v algoritmickém jazyce C; vlastnosti použití MPI pro algoritmický jazyk Fortran budou uvedeny v části 5.8.1,
  • Stručný popis dostupných implementací knihoven MPI a obecný popis prováděcího prostředí programů MPI bude probrán v části 5.8.2.
  • Hlavní prezentace schopností MPI bude zaměřena na standard verze 1.2 ( MPI-1); další vlastnosti standardu verze 2.0 budou uvedeny v článku 5.8.3.

Při zahájení studia MPI lze poznamenat, že na jedné straně je MPI poměrně složitý - standard MPI zajišťuje přítomnost více než 125 funkcí. Na druhou stranu je struktura MPI pečlivě promyšlená – vývoj paralelních programů může začít již po zvážení pouhých 6 funkcí MPI. Se zvyšující se složitostí vyvíjených algoritmů a programů lze zvládnout všechny další funkce MPI. V tomto stylu – od jednoduchých po komplexní – budou dále prezentovány všechny vzdělávací materiály o MPI.

5.2. Úvod do vývoje paralelních programů pomocí MPI

5.2.1. Základy MPI

Uveďme minimální požadovanou sadu MPI funkcí, postačující pro vývoj vcelku jednoduchých paralelních programů.

5.2.1.1 Inicializace a ukončení programů MPI

První funkce volána MPI by měla být funkce:

int MPI_Init (int *agrc, char ***argv);

k inicializaci prostředí pro provádění programu MPI. Parametry funkce jsou počet argumentů na příkazovém řádku a samotný text příkazového řádku.

Poslední volaná funkce MPI musí být funkce:

int MPI_Finalize(void);

V důsledku toho lze poznamenat, že struktura paralelního programu vyvinutého pomocí MPI by měla mít následující podobu:

#include "mpi.h" int main (int argc, char *argv) (<программный код без использования MPI функций>MPI_Init(&agrc, &argv);<программный код с использованием MPI функций>MPI_Finalize();<программный код без использования MPI функций>návrat 0; )

Je třeba poznamenat:

  1. Soubor mpi.h obsahuje definice pojmenovaných konstant, funkčních prototypů a datových typů knihovny MPI,
  2. Funkce MPI_Init A MPI_Finalize jsou povinné a musí být provedeny (a pouze jednou) každým procesem paralelního programu,
  3. Před hovorem MPI_Init funkci lze použít MPI_Inicializováno abyste zjistili, zda již byl hovor uskutečněn MPI_Init.

Výše uvedené příklady funkcí dávají představu o syntaxi pojmenování funkcí v MPI. Před názvem funkce je předpona MPI, za kterou následuje jedno nebo více slov názvu, první slovo názvu funkce začíná velkým znakem a slova jsou oddělena podtržítkem. Názvy funkcí MPI zpravidla vysvětlují účel akcí prováděných funkcí.

Je třeba poznamenat:

  • Komunikátor MPI_COMM_WORLD, jak bylo uvedeno dříve, je vytvořen ve výchozím nastavení a představuje všechny procesy paralelního programu, který se provádí,
  • Pořadí získané pomocí funkce MPI_Comm_rank, je hodnost procesu, který tuto funkci zavolal, tj. variabilní ProcRank bude mít různé hodnoty v různých procesech.
  • Tutorial

V tomto příspěvku budeme hovořit o organizaci výměny dat pomocí MPI na příkladu knihovny Intel MPI. Myslíme si, že tyto informace budou zajímat každého, kdo se chce v praxi seznámit s oblastí paralelních vysoce výkonných výpočtů.

Uvedeme stručný popis toho, jak je organizována výměna dat v paralelních aplikacích založených na MPI, a také odkazy na externí zdroje s podrobnějším popisem. V praktické části naleznete popis všech fází vývoje demo aplikace „Hello World“ MPI, počínaje nastavením potřebného prostředí a konče spuštěním samotného programu.

MPI (rozhraní pro předávání zpráv)

MPI je rozhraní pro předávání zpráv mezi procesy vykonávajícími stejný úkol. Je určen především pro distribuované paměťové systémy (MPP) na rozdíl například od OpenMP. Distribuovaný (clusterový) systém je zpravidla souborem výpočetních uzlů propojených vysoce výkonnými komunikačními kanály (například InfiniBand).

MPI je nejběžnější standard datového rozhraní pro paralelní programování. Standardizaci MPI provádí fórum MPI. Existují implementace MPI pro většinu moderních platforem, operačních systémů a jazyků. MPI je široce používán při řešení různých problémů ve výpočetní fyzice, farmacii, vědě o materiálech, genetice a dalších oblastech poznání.

Z pohledu MPI je paralelní program soubor procesů běžících na různých výpočetních uzlech. Každý proces je vytvořen ze stejného programového kódu.

Hlavní operací v MPI je předávání zpráv. MPI implementuje téměř všechny základní komunikační vzorce: point-to-point, kolektivní a jednostranné.

Práce s MPI

Podívejme se na živý příklad toho, jak je strukturován typický program MPI. Jako ukázkovou aplikaci si vezměme příklad zdrojového kódu dodávaného s Intel MPI Library. Než spustíme náš první program MPI, musíme připravit a nastavit pracovní prostředí pro experimenty.

Nastavení prostředí clusteru

Pro experimenty budeme potřebovat dvojici výpočetních uzlů (nejlépe s podobnými vlastnostmi). Pokud nemáte po ruce dva servery, můžete vždy využít cloudové služby.

Pro ukázku jsem zvolil službu Amazon Elastic Compute Cloud (Amazon EC2). Amazon poskytuje novým uživatelům bezplatný zkušební rok serverů základní úrovně.

Práce s Amazon EC2 je intuitivní. Máte-li jakékoli dotazy, můžete se podívat na podrobnou dokumentaci (v angličtině). V případě potřeby můžete použít jakoukoli jinou podobnou službu.

Vytváříme dva funkční virtuální servery. V konzole pro správu vyberte Virtuální servery EC2 v cloudu, pak Spusťte instanci("Instance" znamená instanci virtuálního serveru).

Dalším krokem je výběr operačního systému. Intel MPI Library podporuje Linux i Windows. Pro první seznámení s MPI zvolíme OS Linux. Vybrat Red Hat Enterprise Linux 6.6 64-bit nebo SLES11.3/12.0.
Vybrat Typ instance(typ serveru). Pro experimenty se nám hodí t2.micro (1 vCPU, 2,5 GHz, rodina procesorů Intel Xeon, 1 GiB RAM). Jako nedávno registrovaný uživatel jsem mohl tento typ používat zdarma – označený jako „Free tier enabled“. Jsme si stanovili Počet instancí: 2 (počet virtuálních serverů).

Poté, co nás služba vyzve ke spuštění Spusťte instance(nakonfigurované virtuální servery), uložíme SSH klíče, které budou potřeba pro komunikaci s virtuálními servery zvenčí. Stav virtuálních serverů a IP adres pro komunikaci s lokálními počítačovými servery lze sledovat v konzole pro správu.

Důležitý bod: v nastavení Síť a zabezpečení / skupiny zabezpečení musíme vytvořit pravidlo, které otevře porty pro připojení TCP – to je potřeba pro správce procesů MPI. Pravidlo může vypadat takto:

Typ: Vlastní pravidlo TCP
Protokol: TCP
Rozsah portů: 1024-65535
Zdroj: 0.0.0.0/0

Z bezpečnostních důvodů můžete nastavit přísnější pravidlo, ale pro naše demo to stačí.

A nakonec krátká anketa o možných tématech pro budoucí publikace o vysoce výkonných počítačích.

Průzkumu se mohou zúčastnit pouze registrovaní uživatelé. , Prosím.

Stalo se, že jsem se zblízka setkal se studiem paralelních výpočtů a zejména MPI. Možná je tento směr dnes velmi nadějný, a tak bych rád hubbrowserům ukázal základy tohoto procesu.

Základní principy a příklad
Jako příklad bude použit výpočet exponenciály (e). Jednou z možností, jak to najít, je Taylorova řada:
e^x=∑((x^n)/n!), kde k součtu dochází od n=0 do nekonečna.

Tento vzorec lze snadno paralelizovat, jelikož požadovaný počet je součtem jednotlivých členů a díky tomu může každý jednotlivý procesor začít jednotlivé členy počítat.

Počet členů, které se budou počítat v každém jednotlivém procesoru, závisí jak na délce intervalu n, tak na dostupném počtu procesorů k, které se mohou zúčastnit procesu výpočtu. Pokud je tedy například délka intervalu n=4 a do výpočtů se zapojí pět procesorů (k=5), pak první až čtvrtý procesor obdrží každý jeden člen a pátý se nepoužije. Pokud n=10 ak=5, každý procesor dostane dva členy pro výpočet.

Zpočátku první procesor pomocí funkce vysílání MPI_Bcast odešle ostatním hodnotu uživatelem zadané proměnné n. Obecně má funkce MPI_Bcast následující formát:
int MPI_Bcast(void *buffer, počet int, datový typ MPI_Datatype, int root, MPI_Comm comm), kde buffer je adresa vyrovnávací paměti s prvkem, počet je počet prvků, datový typ je odpovídající datový typ v MPI, root je hodnost hlavního procesoru, který zajišťuje předávání, a comm je jméno komunikátoru.
V mém případě bude rolí hlavního procesoru, jak již bylo zmíněno, první procesor s hodností 0.

Po úspěšném odeslání čísla n začne každý procesor vypočítávat své podmínky. Za tímto účelem se v každém kroku cyklu k číslu i, které se zpočátku rovná hodnosti procesoru, přičte číslo rovné počtu procesorů účastnících se výpočtů. Pokud číslo i v následujících krocích překročí uživatelem zadané číslo n, provádění smyčky pro tento procesor se zastaví.

Během provádění cyklu budou termíny přidány do samostatné proměnné a po jejím dokončení bude výsledná částka odeslána hlavnímu procesoru. K tomu bude použita funkce operace redukce MPI_Reduce. Obecně to vypadá takto:
int MPI_Reduce(void *buf, void *výsledek, počet int, datový typ MPI_Datatype, MPI_Op op, int root, MPI_Comm comm)

Zřetězí prvky vstupní vyrovnávací paměti každého procesu ve skupině pomocí operace op a vrátí kombinovanou hodnotu do výstupní vyrovnávací paměti kořenového čísla procesu. Výsledkem takové operace bude jediná hodnota, proto dostala funkce přetypování svůj název.

Po spuštění programu na všech procesorech obdrží první procesor celkový součet členů, což bude hodnota exponentu, kterou potřebujeme.

Je třeba poznamenat, že v paralelních i sekvenčních metodách výpočtu exponentu se k nalezení faktoriálu používá rekurzivní funkce. Při rozhodování, jak paralelizovat prováděnou úlohu, jsem zvažoval možnost najít faktoriál i na různých procesorech, ale nakonec mi tato možnost přišla iracionální.

Primárním úkolem je stále zjistit hodnotu exponentu a pokud procesory začnou počítat každý faktoriál každého členu zvlášť, může to vést k přesně opačnému efektu, a to k výrazné ztrátě výkonu a rychlosti výpočtu.
Vysvětluje se to tím, že v tomto případě bude velmi velké zatížení komunikačního prostředí, které je již v paralelních výpočetních systémech často slabým článkem. Pokud je faktoriál vypočítáván soukromě na každém procesoru, bude zatížení komunikačních linek minimální. Tento případ lze nazvat dobrým příkladem toho, že úloha paralelizace musí mít také někdy své meze.

Algoritmus spouštění kódu
1. Hodnota čísla n je přenesena z vizuálního shellu do programu, který je poté odeslán do všech procesorů pomocí funkce broadcast.
2. Když je inicializován první hlavní procesor, spustí se časovač.
3. Každý procesor provádí smyčku, kde hodnota přírůstku je počet procesorů v systému. Při každé iteraci smyčky se vypočítá člen a součet těchto termínů se uloží do proměnné drobSum.
4. Po dokončení smyčky každý procesor přidá svou hodnotu drobSum do proměnné Result pomocí funkce snížení MPI_Reduce.
5. Po dokončení výpočtů na všech procesorech první hlavní procesor zastaví časovač a odešle výslednou hodnotu proměnné Result do výstupního proudu.
6. Časová hodnota naměřená naším časovačem v milisekundách je také odeslána do výstupního proudu.
Výpis kódu
Program je napsán v C++, budeme předpokládat, že argumenty pro spuštění jsou předány z externího shellu. Kód vypadá takto:
#zahrnout "mpi.h"
#zahrnout
#zahrnout
pomocí jmenného prostoru std;

dvojitý fakt (int n)
{
jestliže (n==0)
návrat 1;
jiný
return n*Fact(n-1);
}

int main(int argc, char *argv)
{
SetConsoleOutputCP(1251);
int n;
int myid;
int numprocs;
int i;
int rc;
long double drob,drobSum=0,Výsledek, součet;
double startwtime = 0,0;
dvojitý endwtime;

N = atoi(argv);

if (rc= MPI_Init(&argc, &argv))
{
cout<< "Chyba spouštění, provádění zastaveno" << endl;
MPI_Abort(MPI_COMM_WORLD, rc);
}

MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);

if (myid == 0)
{

Startwtime = MPI_Wtime();
}
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);

pro (i = myid; i<= n; i += numprocs)
{
drob = 1/Fakt(i);
drobSum += drob;
}

MPI_Reduce(&drobSum, &Výsledek, 1, MPI_LONG_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
cout.precision(20);
if (myid == 0)
{
cout<< Result << endl;
endwtime = MPI_Wtime();
cout<< (endwtime-startwtime)*1000 << endl;
}

MPI_Finalize();
návrat 0;
}


* Tento zdrojový kód byl zvýrazněn pomocí Zvýrazňovače zdrojového kódu.
Závěr
Dostali jsme tak jednoduchý program pro výpočet exponentu pomocí více procesorů najednou. Úzkým místem je pravděpodobně samotné uložení výsledku, protože s nárůstem počtu číslic nebude ukládání hodnoty pomocí standardních typů triviální a toto místo vyžaduje rozpracování. Možná docela racionálním řešením je zapsat výsledek do souboru, i když s ohledem na čistě výchovnou funkci tohoto příkladu tomu není třeba věnovat velkou pozornost.

funkce MPI

Odvozený typ, operace, datové typy

Bsend Buffer_attach Get_count ANY_SOURCE Sendrecv_replace ANY_TAG Probe

Allgetherv Alltoall Alltoallv Snížit Rduce_scatter Scan

Odvozený typ je konstruován z předdefinovaných typů MPI a dříve definovaných odvozených typů pomocí speciálních funkcí konstruktoru

MPI_Type_contiguous, MPI_Type_vector, MPI_Type_hvector, MPI_Type_indexed, MPI_Type_hindexed, MPI_Type_struct.

Nový odvozený typ je zaregistrován voláním funkce MPI_Type_commit. Teprve po registraci lze nový odvozený typ použít v komunikačních rutinách a při konstrukci dalších typů. Předdefinované typy MPI jsou považovány za registrované.

Když odvozený typ již není potřeba, je zničen pomocí funkce MPI_Type_free.

1) MPI_Init - inicializační funkce. V důsledku provedení této funkce je vytvořena procesní skupina, do které jsou umístěny všechny aplikační procesy, a vytvořena komunikační oblast popsaná předdefinovaným komunikátorem MPI_COMM_WORLD.

MPI_Type_commit - registrace typu, MPI_Type_free - zničení typu

int MPI_Init(int *argc, char ***argv);

2) MPI_Finalize - Funkce pro dokončení programů MPI. Funkce uzavírá všechny procesy MPI a eliminuje všechny komunikační oblasti.

int MPI_Finalize(void);

3) Funkce pro stanovení počtu procesů v komunikační oblasti MPI_Comm_size . Funkce vrací počet procesů v komunikační oblasti komunikátoru comm.

int MPI_Comm_size(MPI_Comm comm, int *velikost);

4) Funkce detekce čísla procesu MPI_Comm_rank . Funkce vrací číslo procesu, který tuto funkci zavolal. Čísla procesů jsou v rozsahu 0..velikost-1.

int MPI_Comm_rank(MPI_Comm comm, int *rank);

5) Funkce zpráv MPI_Send. Funkce odešle počet prvků datového typu zprávy s identifikátorem tag ke zpracování cíle v komunikační oblasti komunikátoru comm.

int MPI_Send(void* buf, počet int, datový typ MPI_Datatype, int cíl, značka int, komunikace MPI_Comm);

6) Funkce příjmu zpráv MPI_Recv. Funkce přijímá počet prvků datového typu zprávy s identifikátorem tag ze zdrojového procesu v komunikační oblasti komunikátoru comm.

int MPI_Recv(void* buf, počet int, typ dat MPI_Datatype, zdroj int, značka int, komunikace MPI_Comm, MPI_Status *stav)

7) Funkce časování (časovač) MPI_Wtime. Funkce vrací astronomický čas v sekundách, který uplynul od určitého bodu v minulosti (referenční bod).

double MPI_Wtime(void)

Funkce pro předávání zpráv mezi procesy se dělí na:

Předpona S (synchronní)

znamená režim synchronního přenosu dat. Operace přenosu dat se ukončí až po ukončení příjmu dat. Funkce je nelokální.

Předpona B (vyrovnávací paměť)

znamená režim přenosu dat s vyrovnávací pamětí. V adresním prostoru procesu odesílání je vytvořena schránka pomocí speciální funkce, která se používá při výměnných operacích. Operace odeslání končí, když jsou data umístěna do této vyrovnávací paměti. Funkce je lokální povahy.

Předpona R (připraveno)

dohodnutý nebo připravený způsob přenosu dat. Operace přenosu dat začíná pouze tehdy, když přijímající procesor nastavil znamení připravenosti přijímat data a zahájil operaci příjmu. Funkce je nelokální.

Předpona I (okamžité)

odkazuje na neblokující operace.

Struktura MPI_Status

Po přečtení zprávy mohou být některé parametry neznámé, například počet přečtených položek, ID zprávy a adresa odesílatele. Tyto informace lze získat pomocí parametru status. Stavové proměnné musí být explicitně deklarovány v programu MPI. V jazyce C je status strukturou typu MPI_Status se třemi poli MPI_SOURCE, MPI_TAG, MPI_ERROR.

8) Chcete-li zjistit počet skutečně přijatých prvků zprávy, musíte použít speciální funkci MPI_Get_count .

int MPI_Get_count (MPI_Status *stav, datový typ MPI_Datatype, int *počet);

9) Parametry přijaté zprávy můžete určit bez jejího čtení pomocí funkce MPI_Probe. int MPI_Probe (zdroj int, značka int, komunikace MPI_Comm, stav MPI *stav);

10) V situacích, kdy si potřebujete vyměňovat data mezi procesy, je bezpečnější použít kombinovanou operaci MPI_Sendrecv . Při této operaci jsou odeslaná data z pole buf nahrazena přijatými daty.

int MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype, int zdroj, MPI_Datatype recvtag, MPI_Comm comm, MPI_Status *status);

11) Funkce pro kontrolu dokončení neblokující operace MPI_Test.

int MPI_Test(MPI_Request *požadavek, int *příznak, MPI_Status *stav);

Toto je místní neblokující operace. Pokud byla operace spojená s požadavkem dokončena, vrátí se příznak = true a status obsahuje informace o dokončené operaci. Pokud kontrolovaná operace nebyla dokončena, vrátí se příznak = false a hodnota status je v tomto případě nedefinovaná.

12) Funkce pro zrušení požadavku bez čekání na dokončení neblokující operace MPI_Request_free.

int MPI_Request_free(MPI_Request *požadavek);

Parametr požadavku je nastaven na MPI_REQUEST_NULL.

13) Dosažení efektivního provádění operace přenosu dat z jednoho procesu do všech procesů programu (vysílání dat) lze dosáhnout pomocí funkce MPI:

int MPI_Bcast(void *buf,int count,MPI_Datatype type,int root,MPI_Comm comm)

Funkce MPI_Bcast vysílá data z vyrovnávací paměti buf obsahující prvky typu count z kořenového adresáře procesu do všech procesů zahrnutých v komunikačním komunikátoru.

14) Pokud potřebujete od kohokoli obdržet zprávu proces odesílání může mít hodnotu MPI_ANY_SOURCE specifikovanou pro zdrojový parametr

15) Pokud je potřeba obdržet zprávu s libovolnou proměnnou, lze u parametru značky zadat hodnotu MPI_ANY_TAG

16) Parametr status umožňuje definovat řadu charakteristik přijaté zprávy:

- status.MPI_SOURCE – hodnost proces odesílání přijaté zprávy,

- status.MPI_TAG - tag přijaté zprávy.

17) Funkce

MPI_Get_coun t(MPI_Status *stav, typ MPI_Datatype, int *počet)

vrací v proměnné počet počet prvků typu typu v přijaté zprávě.

18) Operace, které přenášejí data ze všech procesů do jednoho procesu. V této operaci na shromážděných

hodnoty provádějí jedno nebo druhé zpracování dat (pro zdůraznění posledního bodu se tato operace také nazývá operace redukce dat)

int MPI_Reduce (void *sendbuf, void *recvbuf,int count,MPI_Datatype type, MPI_Op op,int root,MPI_Comm comm)

19) Synchronizace procesů, tzn. současné dosažení určitých bodů procesu výpočtu procesy je zajištěno pomocí funkce MPI: int MPI_Barrier(MPI_Comm comm); Funkce MPI_Barrier definuje hromadnou operaci, a proto při použití musí být volána všemi procesy použitého komunikátoru. Při volání funkce MPI_Barrier

provádění procesu je zablokováno; výpočty procesů budou pokračovat až poté, co všechny procesy komunikátoru zavolají funkci MPI_Barrier.

20) Chcete-li použít režim přenosu s vyrovnávací pamětí, je nutné vytvořit a přenést vyrovnávací paměť MPI

do bufferu zpráv – funkce použitá k tomu vypadá takto: int MPI_Buffer_attach (void *buf, int size),

- vyrovnávací paměť buf pro ukládání zpráv do vyrovnávací paměti,

- size – velikost vyrovnávací paměti.

21) Po ukončení práce s bufferem je nutné jej odpojit od MPI pomocí funkce:

int MPI_Buffer_detach (void *buf, int *velikost).

22) Dosažení efektivního a zaručeného současného provádění operací přenosu a příjmu dat lze dosáhnout pomocí funkce MPI:

int MPI_Sendrecv (void *sbuf,int scount,MPI_Datatype stype,int dest, int stag, void *rbuf,int rcount,MPI_Datatype

rtype,int source,int rtag, MPI_Comm comm, MPI_Status *status)

23) Pokud jsou zprávy stejného typu, MPI má schopnost používat jednu vyrovnávací paměť: intMPI_Sendrecv_replace (void *buf, počet int, typ MPI_Datatype, int dest,

int stag, int source, int rtag, MPI_Comm comm, MPI_Status* status)

24) Zobecněný provoz přenosu dat z jednoho procesu do všech procesů (distribuce dat) se od vysílání liší tím, že proces přenáší různá data do procesů (viz obr. 4.4). Tuto operaci lze provést pomocí funkce:

int MPI_Scatter (void *sbuf,int scount, typ MPI_Datatype,

25) Operace zobecněného přenosu dat ze všech procesorů do jednoho procesu (sběr dat) je obrácená k postupu distribuce dat (viz obr. 4.5). K provedení této operace v MPI existuje funkce:

int MPI_Gather (void *sbuf,int scount, typ MPI_Datatype,

void *rbuf,int rcount,MPI_Datatype rtype, int root, MPI_Comm comm)

26) Je třeba poznamenat, že při použití funkce MPI_Gather se provádí pouze sběr dat

na jednom procesu. Získat všechna shromážděná data o každém z procesů komunikátoru

musíte použít funkci sběru a distribuce:

int MPI_Allgather (void *sbuf, int scount, typ MPI_Datatype, void *rbuf, int rcount, MPI_Datatype rtype, MPI_Comm comm)

27) Přenos dat ze všech procesů do všech procesů je nejběžnější operací přenosu dat (viz obrázek 4.6). Tuto operaci lze provést pomocí funkce:

int MPI_Alltoall (void *sbuf,int scount,MPI_Datatype typ, void *rbuf,int rcount,MPI_Datatype rtype,MPI_Comm comm)

28) Funkce MPI_Reduce poskytuje výsledky redukce dat

pouze v jednom procesu. Chcete-li získat výsledky redukce dat na každém z procesů komunikátoru, musíte použít funkci redukce a distribuce:

int MPI_Allreduce (void *sendbuf, void *recvbuf,int count, typ MPI_Datatype, MPI_Op op, MPI_Comm comm).

29) A další verzi operace sběru a zpracování dat, která zajišťuje získání všech dílčích výsledků redukce, lze získat pomocí funkce:

int MPI_Scan (void *sendbuf, void *recvbuf,int count, typ MPI_Datatype, MPI_Op op, MPI_Comm comm).

Obecný prováděcí diagram funkce MPI_Scan je na Obr. 4.7. Prvky přijatých zpráv představují výsledky zpracování odpovídajících prvků zpráv přenášených procesy a získání výsledků na procesu s úrovní i, 0≤i

30) Počáteční hodnota proměnné bufpos musí být vytvořena před začátkem balení a poté je nastavena funkcí MPI_Pack. Funkce MPI_Pack je volána postupně, aby sbalila všechna potřebná data.

int MPI_Pack_size (počet int, typ MPI_Datatype, MPI_Comm comm, int *velikost)

31) Po sbalení všech potřebných dat lze připravený buffer použít ve funkcích přenosu dat se zadaným typem MPI_PACKED.

Po obdržení zprávy typu MPI_PACKED lze data rozbalit pomocí funkce:

int MPI_Unpack (void *buf, int bufsize, int *bufpos, void *data, počet int, typ MPI_Datatype, MPI_Comm comm)

Počítač s komplexní instrukční sadou

CISC (anglicky Complex Instruction Set Computing nebo anglicky Complex Instruction Set Computer -

počítač s úplnou sadou instrukcí) je koncept návrhu procesoru, který se vyznačuje následující sadou vlastností:

relativně malý počet registrů pro všeobecné použití;

· velké množství strojových instrukcí, z nichž některé jsou načteny sémanticky podobně jako operátory programovacích jazyků na vysoké úrovni a jsou prováděny v mnoha hodinových cyklech;

· velké množství metod adresování;

· velké množství příkazových formátů různých bitových velikostí;

· převaha formátu příkazu se dvěma adresami;

· přítomnost příkazů pro zpracování typu registr-paměť.

nedostatky:

vysoké náklady na hardware; potíže s paralelizací výpočtů.

Technika konstrukce instrukčního systému CISC je opakem jiné techniky - RISC. Rozdíl mezi těmito koncepty spočívá v metodách programování, nikoli ve skutečné architektuře procesoru. Téměř všechny moderní procesory emulují instrukční sady typu RISC i CISC.

Omezené pokyny Set Computer

Je založen na principech architektury RISC: pevný formát instrukcí, operace s registry, jednocyklové provádění instrukcí, jednoduché metody adresování a velký soubor registrů. Zároveň existuje několik významných vlastností, které odlišují tuto architekturu od architektur jiných RISC procesorů. Mezi ně patří: nezávislá sada registrů pro každý z pohonů; zahrnutí jednotlivých instrukcí podobných CISC do systému; nedostatek mechanismu „zpožděného přechodu“; originální způsob implementace podmíněných skoků. Hlavními aplikacemi mikroprocesorových architektur jsou vysoce výkonné servery a superpočítače.

Takové počítače byly založeny na architektuře, která oddělovala instrukce pro zpracování od instrukcí paměti a kladla důraz na efektivní zřetězení. Instrukční systém byl navržen tak, aby provedení jakékoli instrukce trvalo malý počet strojových cyklů (nejlépe jeden strojový cyklus). Samotná logika pro provádění příkazů za účelem zvýšení výkonu byla zaměřena spíše na hardware než na implementaci firmwaru. Pro zjednodušení logiky dekódování příkazů byly použity příkazy s pevnou délkou

A pevný formát.

V Jaký je smysl technologie přechodu cílové adresy?

V Procesor poskytuje mechanismus pro dynamickou předpověď směru přechodů. S tím

Cílem na čipu je malá mezipaměť nazývaná vyrovnávací paměť cíle (BTB) a dva nezávislé páry vyrovnávacích pamětí předběžného načítání instrukce (dvě 32bitové vyrovnávací paměti na kanál). Ve vyrovnávací paměti cílové adresy větve jsou uloženy adresy instrukcí, které jsou ve vyrovnávací paměti předběžného načítání. Činnost vyrovnávacích pamětí předběžného načítání je organizována tak, že v každém daném okamžiku jsou instrukce vyzvednuty pouze do jedné z vyrovnávacích pamětí odpovídajícího páru. Když je v toku instrukcí detekována operace větvení, je vypočtená adresa větvení porovnána s adresami uloženými ve vyrovnávací paměti BTB. Pokud existuje shoda, předpokládá se, že se uskuteční větvení a povolí se další vyrovnávací paměť předběžného načtení a začne vydávat příkazy do odpovídajícího kanálu k provedení. Pokud dojde k neshodě, předpokládá se, že větev nebude provedena a nevyrovnávací paměť předběžného načtení nebude přepnuta, což pokračuje v normálním příkazu. Tím se zabrání prostojům dopravníku

Strukturální konflikty a způsoby jejich minimalizace

Kombinovaný režim provádění příkazů obecně vyžaduje zřetězení funkčních jednotek a duplikaci zdrojů k vyřešení všech možných kombinací příkazů v řetězci. Pokud jakákoli kombinace příkazů selže

být přijat kvůli konfliktu zdrojů, pak se o stroji říká, že má strukturální konflikt. Nejtypičtějším příkladem strojů, u kterých může dojít ke strukturálním konfliktům, jsou stroje s funkčními zařízeními, která nejsou plně dopravníková.

Minimalizace: Potrubí pozastaví provádění jednoho z příkazů, dokud nebude k dispozici požadované zařízení.

Konflikty dat, zastavení potrubí a implementace mechanismu bypassu

Jedním z faktorů, který má významný vliv na výkon dopravníkových systémů, jsou meziinstrukční logické závislosti. Ke konfliktům dat dochází, když použití zpracování zřetězení může změnit pořadí volání operandů tak, že se toto pořadí liší od pořadí, které je pozorováno, když jsou instrukce prováděny postupně na nezřetězeném stroji. Problém uvedený v tomto příkladu lze vyřešit pomocí poměrně jednoduché hardwarové techniky zvané předávání dat, obcházení dat nebo někdy zkratování.

Konflikty dat způsobí pozastavení kanálu

Místo toho potřebujeme další hardware, tzv. pipeline interlook hardware, abychom zajistili správné fungování příkladu. Obecně platí, že tento druh zařízení detekuje konflikty a pozastaví potrubí, dokud konflikt existuje. V tomto případě tento hardware pozastaví kanál počínaje instrukcí, která chce použít data, zatímco předchozí instrukce, jejímž výsledkem je náš operand, tento výsledek vytvoří. Toto zařízení způsobí, že se výrobní linka zastaví nebo se objeví „bublina“ stejným způsobem jako v případě strukturálních konfliktů.

Vyrovnávací paměti podmíněné predikce větvení

Vyrovnávací paměť podmíněné predikce větvení je malá paměť adresovatelná nejméně významnými bity adresy instrukce větvení. Každá buňka této paměti obsahuje jeden bit, který udává, zda byla provedena předchozí větev či nikoliv. Jedná se o nejjednodušší typ vyrovnávací paměti tohoto druhu. Nemá žádné značky a je užitečný pouze pro snížení latence větve v případě, že je zpoždění delší než čas potřebný k výpočtu hodnoty cílové adresy větve. Vyrovnávací paměť predikce větvení může být implementována jako malá vyhrazená mezipaměť, ke které přistupuje adresa instrukce během fáze vyzvednutí instrukce potrubí (IF), nebo jako dvojice bitů sdružených s každým blokem mezipaměti instrukce a vyzvednuta s každou instrukcí.




Horní