Cvičení předmětu MI-PAR P. Tvrdík, I. Šimeček, M. Šoch

Podobné dokumenty
Ústav technické matematiky FS ( Ústav technické matematiky FS ) / 35

4. Rekurze. BI-EP1 Efektivní programování Martin Kačer

Rekurzivní algoritmy

Struktura programu v době běhu

Programování založené na posílání zpráv

Dynamické programování

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 21.

Zpráva o průběhu přijímacího řízení na vysokých školách dle Vyhlášky MŠMT č. 343/2002 a její změně 276/2004 Sb.

Časová a prostorová složitost algoritmů

int ii char [16] double dd název adresa / proměnná N = nevyužito xxx xxx xxx N xxx xxx N xxx N

Přednáška. Správa paměti II. Katedra počítačových systémů FIT, České vysoké učení technické v Praze Jan Trdlička, 2012

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 12.

Funkce pokročilé možnosti. Úvod do programování 2 Tomáš Kühr

Princip funkce počítače

Algoritmus pro hledání nejkratší cesty orientovaným grafem

Spojová implementace lineárních datových struktur

Programování v jazyce C a C++

Přednáška. Vstup/Výstup. Katedra počítačových systémů FIT, České vysoké učení technické v Praze Jan Trdlička, 2012

Přednáška 3. Rekurze 1

Řešení: PŘENESVĚŽ (N, A, B, C) = přenes N disků z A na B pomocí C

Datové struktury 2: Rozptylovací tabulky

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

Implementace LL(1) překladů

Pole a Funkce. Úvod do programování 1 Tomáš Kühr

Prohledávání do šířky = algoritmus vlny

Martin Flusser. Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague. December 7, 2016

Základní datové struktury III: Stromy, haldy

Dynamicky vázané metody. Pozdní vazba, virtuální metody

Dynamické datové struktury IV.

1 Definice problému a popis sekvenčního algoritmu

Procesy a vlákna (Processes and Threads)

NP-ÚPLNÉ PROBLÉMY. Doc. RNDr. Josef Kolář, CSc. Katedra teoretické informatiky, FIT České vysoké učení technické v Praze

SEMESTRÁLNÍ PROJEKT Y38PRO

Úvod do programování - Java. Cvičení č.4

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Stromy, haldy, prioritní fronty

5 Rekurze a zásobník. Rekurzivní volání metody

Lineární spojový seznam (úvod do dynamických datových struktur)

Operační systémy. Jednoduché stránkování. Virtuální paměť. Příklad: jednoduché stránkování. Virtuální paměť se stránkování. Memory Management Unit

Vlákno (anglicky: thread) v informatice označuje vlákno výpočtu neboli samostatný výpočetní tok, tedy posloupnost po sobě jdoucích operací.

Cvičení MI-PRC I. Šimeček

Algoritmy výpočetní geometrie

Test prvočíselnosti. Úkol: otestovat dané číslo N, zda je prvočíslem

OPS Paralelní systémy, seznam pojmů, klasifikace

Operační systémy. Cvičení 4: Programování v C pod Unixem

Martin Lísal. Úvod do MPI

Paralení programování pro vícejádrové stroje s použitím OpenMP. B4B36PDV Paralelní a distribuované výpočty

VYŠŠÍ ODBORNÁ ŠKOLA a STŘEDNÍ PRŮMYSLOVÁ ŠKOLA Mariánská 1100, Varnsdorf PROGRAMOVÁNÍ FUNKCE, REKURZE, CYKLY

Více o konstruktorech a destruktorech

Systém adresace paměti

Základní datové struktury

TÉMATICKÝ OKRUH Softwarové inženýrství

Algoritmizace a programování

Kolekce, cyklus foreach

12. Globální metody MI-PAA

Algoritmy a datové struktury

VYSOKÁ ŠKOLA BÁŇSKÁ TECHNICKÁ UNIVERZITA OSTRAVA FAKULTA STROJNÍ DATABÁZOVÉ SYSTÉMY ARCHITEKTURA DATABÁZOVÝCH SYSTÉMŮ. Ing. Lukáš OTTE, Ph.D.

Vlákna a přístup ke sdílené paměti. B4B36PDV Paralelní a distribuované výpočty

Základy programování (IZP)

Rekurze. Jan Hnilica Počítačové modelování 12

Algoritmizace Dynamické programování. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010

Čtvrtek 8. prosince. Pascal - opakování základů. Struktura programu:

Tento studijní blok má za cíl pokračovat v základních prvcích jazyka Java. Konkrétně bude věnována pozornost rozhraním a výjimkám.

Stromy. Strom: souvislý graf bez kružnic využití: počítačová grafika seznam objektů efektivní vyhledávání výpočetní stromy rozhodovací stromy

Základní komunikační operace

Funkce, intuitivní chápání složitosti

Knihovna EpsnetLib TXV první vydání září 2012 změny vyhrazeny

přetížení operátorů (o)

Semestrální práce z KIV/PC. Kolja Matuševský (A14B0310P)

java remote method invocation Kateřina Fricková, Matouš Jandek

ALGORITMIZACE 2010/03 STROMY, BINÁRNÍ STROMY VZTAH STROMŮ A REKURZE ZÁSOBNÍK IMPLEMENTUJE REKURZI PROHLEDÁVÁNÍ S NÁVRATEM (BACKTRACK)

IUJCE 07/08 Přednáška č. 6

Binární soubory (datové, typované)

Základy programování. Úloha: Eratosthenovo síto. Autor: Josef Hrabal Číslo: HRA0031 Datum: Předmět: ZAP

Cvičení MI-PAP I. Šimeček, M. Skrbek, J. Trdlička

Distribuované systémy a výpočty

Programování v jazyce C pro chemiky (C2160) 3. Příkaz switch, příkaz cyklu for, operátory ++ a --, pole

Jazyk C práce se soubory. Jan Hnilica Počítačové modelování 16

Martin Flusser. Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague. October 17, 2016

Dynamické datové struktury III.

Vyučovací hodina. 1vyučovací hodina: 2vyučovací hodiny: Opakování z minulé hodiny. Procvičení nové látky

Algoritmy. Z. Sawa (VŠB-TUO) Úvod do teoretické informatiky 15. dubna / 39

8 Třídy, objekty, metody, předávání argumentů metod

Rekurze. Pavel Töpfer, 2017 Programování 1-8 1

Úvod do MPI. Úvod do MPI Operace send a recieve Blokující a neblokující posílání zpráv Blokující posílání zpráv Neblokující posílání zpráv

Simulace číslicových obvodů (MI-SIM) zimní semestr 2010/2011

Příklad aplikace Klient/Server s Boss/Worker modelem (informativní)

Lineární datové struktury

Abstraktní třídy, polymorfní struktury

TECHNICKÁ UNIVERZITA V LIBERCI

NMIN102 Programování /2 Z, Zk

INFORMAČNÍ SYSTÉM VIDIUM A VYUŽITÍ MODERNÍCH TECHNOLOGIÍ

Od CGI k FastCGI. Uvedené dílo podléhá licenci Creative Commons Uved te autora 3.0 Česko.

Standardní algoritmy vyhledávací.

Cílem kapitoly je seznámit studenta se seznamem a stromem. Jejich konstrukci, užití a základní vlastnosti.

Používejte jen ty konstrukty jazyka C/C++, které jsme doposud probírali (nepoužívejte STL apod.)

Algoritmy a datové struktury

Unity a Objekty (NMIN102) RNDr. Michal Žemlička, Ph.D.

Konstruktory a destruktory

Transkript:

Cvičení předmětu MI-PAR P. Tvrdík, I. Šimeček, M. Šoch pavel.tvrdik,xsimecek,soch@fit.cvut.cz Katedra počítačových systémů FIT České vysoké učení technické v Praze 2011 MI-PAR, ZS2011/12, Cv.1-6 Příprava studijního programu Informatika je podporována projektem financovaným z Evropského sociálního fondu a rozpočtu hlavního města Prahy. Praha & EU: Investujeme do vaší budoucnosti

1 of 4 22.12.2011 13:10 Jak na sekvenční část Úlohy obecně vedou na prohledávání stavového prostoru do hloubku. Tento postup se nejlépe implementuje pomocí rekurzivního algoritmu. Není nic jednodušího, než napsat rekurzivní funkci, která svým vlastním voláním dokáže kompletně projít stavový prostor a najít požadované řešení. Při volání rekurzivní funkce se vždy všechny požadované proměnné ukládají na zásobník (na systemový zásobník, který obsluhuje operační systém na základě vygenerovaných instrukcí). Toto je z hlediska následné paralelizace zasadní nevýhoda implementace pomocí rekurzivní funkce. Pro úspěšnou paralelní implementaci rekurzivního proledávání musíme zvolit jinou metodu než pomocí rekurzivní funkce. Rekurzivní prohledávání můžeme zapsat pomocí iterativního cyklu (pravděpodobně while) v kombinaci s použitím vlastního zásobníku (tento zasobník naimplementujte sami nebo použijte standardní implementaci z dostupných knihoven, např. STL). Následující slides ukazují příklad implementace prohledávání stavového prostoru jak pomoci rekurzivní fukce, tak i iterativním cyklem. Všimněte si možnosti ořezávání neperspektivních větví. Je-li tento test jednoduchý, nezapomeňte ho také ve své úloze naimplementovat. Paměťová versus časová složitost Je těžké napsat algoritmus, který bude současně časově i paměťově efektivní. Oba dva požadavky jdou často proti sobě. Je potřeba se rozhodnout, kterému parametru při implementaci dáme přednost. Protože fyzická paměť pracovních stanic je omezená a není zrovna velká, bylo by vhodné si při implementaci vašich úloh dávat pozor na paměťove nároky. Paměťová složitost se nejvíce projeví při implementaci zásobníku. Ne ale tím jak zvolit samotnou reprezentaci zásobníku - statické pole, dynamicky alokované struktury - ale paměťová složitost je daná tím, co a v jakém množství budeme do zásobníku ukládat. Množství a velikost položek určí z velké části celkovou paměťovou složitost vaší implementace. Implementace zásobníku Zásobník lze implementovat několika různými způsoby. Je třeba si uvědomit, že prohledávaný stavový prostor je velký a tudíž paměťové nároky na implmentaci zásobníku mohou být velké. Tomu je třeba implementaci zásobníku uzpůsobit, aby fyzická paměť pracovních stanic vůbec pro výpočet stačila. Podívejme se na tento problém blíže. Pro demostraci použijme problém Magického čtverce pro n=3 (stejně jako u diskuze o nevhodnosti rekurze). - Při expanzi do zásobníku vložíte vždy celá pole, která odpovídají celým konfiguracím rozpracovaného magického čtverce. Nebo-li pro první vkládané číslo i=9 vložíte do vrchního patra zásobníku 9 kopií pole 3 3 s různě rozmístěnými devítkami. Z hlediska paměťového vložíme na zásobník 9*3*3=81 prvků. Budeme-li předpokládat že jeden prvek je integer o 4 bytech, vložíme do zásobníku tedy 324 bytů. 1. Při expanzi do zásobníku vložíte vždy pouze indexy, na které pozice dané číslo umísťujete. Pole s čísly máte pouze jedno globální a v připadě potřeby pracujete vždy pouze s ním, nebo-li při expanzi na danou pozici vložíte požadované číslo a při návratu z dané pozice číslo vyjmete a pozici v globálním poli uvolníte. Za předpokladu, že index budeme reprezentovat dvojicí čísel (x a y), tak z hlediska paměťového vložíme na zásobník 9*2=18 prvků. Budeme-li předpokládat že jeden prvek je integer o 4 bytech, vložíme do zásobníku tedy 72 bytů. Je evidentní, že z uvedených metod je výhodnější a k paměti šetrnější metoda 2). Vždy se snažte mít jedno globální pole, které bude reprezentovat hrací plán, graf či jinou strukturu, která definuje váš problém, a do zásobníku ukládejte minimum informací, z kterých budete vždy schopni zrestaurovat změny v globálním poli. Volbu, zda implementaci provedete staticky (pole) či dynamicky, zvolte na základě odhadu velikosti zásobníku. Jak na paralelní část

2 of 4 22.12.2011 13:10 Při paralelním řešení je stejná aplikace (míněno přeložený binární soubor) spuštěna na více pracovních stanicích. Procesy mezi sebou nesdílejí žádná data - neexistuje sdílená paměť. Jediné, co mají procesy společné, je komunikační síť, která stanice spojuje, a procesy ji mohou využívat pro výměnu dat. Jedná se tedy o model paralelního počítače s distribuovanou pamětí. Při realizaci paralelní implementace se vychází ze sekvenčního řešení. Z globálního pohledu je potřeba do implementace přidat: Podporu výměny dat po síti. V okamžiku, kdy procesu dojde lokální výpočet, umět požádat o další práci (nebo-li získat kus zásobníku jiného procesu s neprojitými stavy). Možnost dělení zásobníku. Rozdělený zásobník odeslat jinému procesu. Přijatou část zásobníku umět zrestaurovat a odstarovat z ní výpočet. Detekovat ukončení výpočtu (nebo-li žádný proces již neprovádí výpočet). Vrátit výsledek uživateli. Podpora výměny dat je zajištěna použitim knihovny MPI [http://users.fit.cvut.cz/~soch/mi-par/]. Při dělení zásobníku se musíte vypořádat s problémem tzv. serializace. Data zásobniku jsou nejspíše heterogenní datové struktury, které pro předávání práce budete muset posílat pomocí MPI zpráv po síti. MPI v zásadě podporuje streamy homogenních dat. Jedna z možností, jak data po síti poslat, je vše přetypovat na typ byte (v jazyce C se jedná vlastně o typ char - MPI_CHAR) a takto natypovaná data ulozit do zprávy a tu odeslat. Po příjmu je samozřejmě potřeba provést zpětné přetypování na správné typy. Druhou možností je s daty pracovat v jejich původnim tvaru a pomocí funkci MPI_Pack (s použitím typu MPI_PACKED) data do zprávy zapakovat položku po položce. Na straně příjmu je potřeba data zase rozpakovat pomocí funkce MPI_Unpack - přesně v tom samém pořadí v jakém byla data poslána. Implementace obsluhy přijímání a odesílání zpráv vede v podstatě na realizaci jednoduchého stavového automatu. Stavy, kterými aplikace prochází, můžeme řídit pomocí tzv. značky (tagu), který funkce MPI_Send dovoluje k jednotlivým zprávám přiřazovat. Na straně příjmu je vhodné použít neblokující MPI_Iprobe, který testuje příchod zprávy. Následně, když je zpráva dostupná, volat blokující MPI_Recv pro samotný příjem dat. Nevolejte MPI_Iprobe během každé expanze, cena této operace je řádově vyšší než cena expanze. Je vhodné si definovat konstantu, která bude říkat jak často se MPI_Iprobe bude volat. Jako výchozí hodnotu zvolte 100. Následně je možné experimentálně najít její optimální hodnotu. Vysledný zdrojový kód může mít schematicky následující podobu: #define CHECK_MSG_AMOUNT 100 #define MSG_WORK_REQUEST 1000 #define MSG_WORK_SENT 1001 #define MSG_WORK_NOWORK 1002 #define MSG_TOKEN 1003 #define MSG_FINISH 1004... while zasobnik_neni_prazdny() citac++; if ((citac % CHECK_MSG_AMOUNT)==0) MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &status); if (flag) //prisla zprava, je treba ji obslouzit //v promenne status je tag (status.mpi_tag), cislo odesilatele (status.mpi_source) //a pripadne cislo chyby (status.mpi_error) swith (status.mpi_tag) case MSG_WORK_REQUEST : // zadost o praci, prijmout a dopovedet // zaslat rozdeleny zasobnik a nebo odmitnuti MSG_WORK_NOWORK case MSG_WORK_SENT : // prisel rozdeleny zasobnik, prijmout // deserializovat a spustit vypocet case MSG_WORK_NOWORK : // odmitnuti zadosti o praci // zkusit jiny proces // a nebo se prepnout do pasivniho stavu a cekat na token

3 of 4 22.12.2011 13:10 break case MSG_TOKEN : //ukoncovaci token, prijmout a nasledne preposlat // - bily nebo cerny v zavislosti na stavu procesu case MSG_FINISH : //konec vypoctu - proces 0 pomoci tokenu zjistil, ze jiz nikdo nema praci //a rozeslal zpravu ukoncujici vypocet //mam-li reseni, odeslu procesu 0 //nasledne ukoncim spoji cinnost //jestlize se meri cas, nezapomen zavolat koncovou barieru MPI_Barrier (MPI_COMM_WORLD) MPI_Finalize(); exit (0); default : chyba("neznamy typ zpravy"); expanduj_dalsi_stavy (); Uvedený zdrojový kód je pouze pomůckou jak při implementaci postupovat. Je samozřejme možné použít i jiné konstrukce a obraty, ale ve vetší či menší míře se uvedenému příkladu budete blížit. MPI samo o sobě nevyrobí logiku aplikace (míněno onen stavový automat či komunikační protokol). Tu právě musíte navrhnout vy. MPI vám ale usnadní přenos dat po síti a oprostí vás od problému s přímým použitím protokolu TCP/IP. Předpokládejte, že komunikační síť počítače STAR a MPI jsou bezchybné entity, data a zprávy se neztrácejí. Nebo-li nezabývejte se error handlingem a zotavením z chyb způsobených špatným přenosem zpráv. V 99% takovéto chyby nezažijete. Většina chyb je způsobena na straně vaší aplikace - většinou se jedná o nepovolený přístup do paměti (pointer je NULL, hodnota pointeru by přenesena pomocí MPI z jiného výpočetního uzlu, pointer není naalokovany, pointer odkazuje na již uvolněnou paměť, apod.). Start výpočtu Nepatrně atypický okamžik nastává při startu výpočtu. MPI spustí požadovaný počet procesů, které budou úlohu řešit. V tu chvíli nikdo nemá práci a ani vstupní data. Jeden proces, např. proces s číslem 0, bude zopovědný za start výpočtu. Načte vstupní data a rozešle je ostatním procesům. Následně začne standardním sekvenčním algoritmem úlohu zpracovávat prohledáváním do hloubky. V okamžiku, kdy má na zásobníku alespoň p volných stavů, tj. stavů určených pro budoucí zpracování, provede rozdělení svého zásobníku a každému procesu zašle jeden volný stav a jeden si nechá pro sebe. V tomto okamžikyu má každý proces jeden stav, který představuje různě velký podstrom stavového prostoru, který má zpracovat. Všechny procesy jsou v tuto chvíli již rovnocené a výpočet běží na všech procesech. MPI (Message Passing Interface) Knihovna MPI, kterou používáme pro implementaci paralelního řešení, Vám zjednoduší práci s posilanim dat mezi procesy. Proč je toto nutné? Je to z toho důvodu, že pracujete na počítači s distribuovanou pamětí. Počítač STAR se skládá ze samostatných PCček (třebaže jsou v blade provedení), které jsou propojeny komunikační sítí. Vaše aplikace, přesněji řečeno procesy, běží na různých výpočetních jádrech, které mezi sebou sdílejí pouze komunikační síť. Jediná možnost, jak si vyměňovat data, je pomocí této sítě (pokud tedy pomineme výměnu dat přes file systém). K tomu by šlo samozřejmě využít přímo rozhraní TCP/IP, ale to by bylo zbytečně složité. Logická nadstavba nad tím je právě knihovna MPI. Samotná knihovna je pouze průmyslový standard, nebo-li soupis prototypů více než 100 funkcí. Každý výrobce specifického paralelního HW si může knihovnu MPI podle této specifikace sám naimplementovat. Jak již bylo zmíňeno, knihovna MPI obsahuje velké množství funkcí. Ve Vaší semestralní úloze můžete použít libovolné funkce, které MPI nabízí a budete je potřebovat. Abyste nemuseli složitě potřebné funkce hledat, následující výčet obsahuje minimum z MPI, které budete potřebova: MPI_Init MPI_Finalize MPI_Comm_rank MPI_Comm_size MPI_Send MPI_Recv MPI_Iprobe

4 of 4 22.12.2011 13:10 Více o programování pod MPI nalezenete zde [http://users.fit.cvut.cz/~soch/mi-par/]. Podpora měření času v MPI Knihovna MPI obsahuje funkci MPI_Wtime, která vrací časové razítko. Získam-li více hodnot, vrácených funkcí MPI_Wtime, tak jejich odečtením získám čas běhu aplikace mezi těmito razítky. Co měřit Duležité je také vědět co měřit a ne jenom jak měřit. Většina aplikací funguje na principu master/slave. Master na začátku výpočtu načítá a distribuuje data, nad kterými se bude výpočet provádět. Na konci výpočtu dochází opět k zasílání již vyhodnocených dat od slavu smerem k masterovi. Tento čas (načítání, rozesílání a shromažďování dat) je potřeba také měřit - i když nejvíce zatěžuje celý systém (jak MPI tak lokální síť), tak je součástí výpočtu. Třebaže celý výpočet je asynchroní, je vhodné všechny procesy zesynchronizovat právě před samotným začátkem výpočtu (samotný výpočet však NESYNCHRONIZOVAT). Uveďme jednoduchý příklad: /*** master ***/ main () double t1, t2; MPI_Barrier (); /* cekam na spusteni vsech procesu */ t1=mpi_wtime (); /* pocatecni cas */ MPI_Send (); /* rozesilam data */ /*... vlastni vypocet... */ MPI_Recv (); /* prijimam data zpet */ MPI_Barrier (); /* cekam na dokonceni vypoctu */ t2=mpi_wtime(); /* koncovy cas */ printf ("Spotrebovany cas je %f.\n",t2-t1); MPI_Finalize (); return (0); /*** slave ***/ main () MPI_Barrier (); /* data jsem dostal */ MPI_Recv (); /* prijimam data od mastera */ /*... vlastni vypocet... */ MPI_Send (); /* posilama data zpet masterovi */ MPI_Barrier (); /* vypocet hotov */ MPI_Finalize (); return (0); /mnt/www/courses/mi-par/data/pages/labs/poznamky_k_implementaci.txt Poslední úprava: 2010/09/19 14:47 autor: xsimecek