Základní úrovně: hardwarová (procesory, jádra) programová (procesy, vlákna) algoritmická (uf...) zvýšení výkonu, redundance, jiné cíle, ale podobné nástroje a problémy. Moorův zákon: Počet tranzistorů/komponent, které lze levně integrovat se zdvojnásobí každý rok. Spíše pravidlo ( strategie intelu). multi-core mikroprocesory (CPU) - zrychlování sekvenčních programů, rozsáhlé univerzální instrukční soubory hypertherading s dvěma a více vlákny zajištění vícevláknového paralelního zpracování strojových instrukcí 1 Fyzické jádro se tváří jako více logických pipeline zřetězení procesů (překrývání), instrukce je rozdělena do více částí procesoru -> více činností. (vyzvednutí instrukce, dekódování instrukce, provedení instrukce, čtení z paměti, zápis výsledku do paměti) many-core mikroprocesory (GPU) - zvyšování propustnosti (throughput) stovky jader, stovky vláken, zaměřeno na floating-point operace Paralelní systém systém, ve kterém může probíhat několik procesů/činností současně Instrukce = příkaz, iterace = opakování, procedura = sekvence instrukcí Proces = kolekce vláken, společný kód + data Vlákno = instance kódu + dat a stav zásobníku + registrů. Vlákna sdílejí pamět -> komunikace Úloha = aplikace? Procesor kolekce jader jádro (core) čip + paměť + řadič vykonávající jedno vlákno multithreaded-core jádro schopné spustit více vláken multiprocesor = procesor s kolekcí multithread-jader Flynnova klasifikace systému Single Instruction, Single Data stream (SISD) data jsou zpracovávána výhradně sériově, instrukce jsou prováděny sériově, stačí jeden CPU, řídicí jednotky klasický von Neumannův počítač Single Instruction, Multiple Data streams (SIMD) - Jedná instrukce se provádí na více datech. Více CPU provádí stejnou instrukci s jinými daty -Typické GPU proc- maticové procesory, array/matrix esor
Multiple Instruction, Single Data stream (MISD) - jedna data jsou předávána více instrukcím více CPU, každý zpracovává data v jiné fázi výrobní linka umělá kategorie - není to pipelining Multiple Single Instruction stream, Multiple Data stream (MSIMD) několik propojených SIMD Same Program, Multiple Data stream (SPMD) každý procesor provádí stejný program, využívají se běžné CPU
Multiple Instruction, Multiple Data streams (MIMD) - Různá CPU mohou provádět různé operace - různá CPU pracují s jinými daty Moderní počítače, Distribuované systémy, HW virtualizace, Grid Komunikace výměna dat mezi paralelně probíhajícími procesy Synchronizace koordinace vláken, provádění příkazů v požadovaném pořadí. Kontrolovaný přístup ke sdíleným zdrojům (paměť). Režie (overhead) paralelismu čas spotřebovaný na komunikaci čas spotřebovaný na synchronizaci a výměnu dat ostatní režie (knihovny, spuštění, zastavení) Škálovatelnost (scalability) míra růstu výkonosti s růstem paralelismu zefektivnění algoritmu s přidáváním paralelizmu Amdahlův zákon předpovězení teoretického maximálního zrychlení při přidávání dalších procesorů. f s f p = 1 f s podíl programu, který nelze paralelizovat f p podíl programu, který lze paralelizovat t celková doba výpočtu p počet procesorů t 1 S z = t f s + t f p p = 1 f p + f p p Možnosti paralelizace Nízko úrovňové (fine grained) pipelining, multithreading, a podobné vychytávky Vyšší úroveň
použití více jader / procesorů - pod 60% f p zcela nezajímavé paralelizace algoritmu zvyšujeme f p - využití speciálního HW (GPU) preemptivní multitasking operační systém přiděluje procesorový čas běžícím vláknům/procesům, v pravidelných časových intervalech (řádově 100 1000x za vteřinu) uspává/probouzí vlákna -> běžící procesy se střídají Serializace - zajištění posloupnosti událostí události se provedou sekvenčně, pokud je zaručeno pořadí jejich provedení události se provedou souběžně, pokud se mohou provést ve stejný čas nebo v různém pořadí souběžně se provádí něco, o čem z kódu nedokážeme říct, který řádek se provede dřív Mutual exclusion vzájemné vyloučení mutex = semaphore(1) Semafor programová struktura, která se hodí pro synchronizaci při vytvoření se nastaví počáteční hodnota, při průchodu se sníží o 1 pokud je hodnota záporná pak se vlákno uspí (will block) pokud se hodnota semaforu zvýší na 0, pak je některé ze spících vláken probuzeno (wake-up) u standardního semaforu nevíme, které vlákno bude probuzeno aktuální hodnotu semaforu nelze zjistit stav semaforu je neurčitý semafor je atomický vlákno buď projde, nebo neprojde hodnota semaforu = počet propustek binární semafor = jedna propustka = mutex může existovat férový semafor, který probudí nejstarší vlákno- zabraňuje stárnutí - u pracovních vláken není moc žádoucí průchod semaforem semafor = semaphore(0) wait() = acquire() = decrement() signal() = release() = increment() bariéra symetrické rendezvous pro libovolný počet vláken všechna vlákna musí počkat, než projdou bodem setkání po příchodu posledního vlákna mohou všichni pokračovat dál realizace n vláken poslední vlákno otevře bariéru praktické využití pracovní vlákna po dokončení práce se výsledky spojí rozdá se nová práce spouští se v cyklu potřebujeme bariéru, kterou lze znovu použít wait v kritické sekci (uvnitř mutexu) je nepoužitelný turniket bod, kterým vlákna prochází po jednom, ale bez zdržení kdy funguje? n=počet vláken kdy nefunguje? předbíhání procesů
mutex = semaphore(1) barrier = semaphore(0) count = count + 1 if count == n barrier.signal() barrier.wait() //přidáním barrier.signal() je turniket Bariéra další řešení count = count + 1 if count == n turnstile.signal(n) turnstile.wait() /* process */ count = count 1 if count == 0 turnstile2.signal(n); turnstile2.wait() Fronta - 2 varianty a) smí pokračovat v párech danou činnost může vyvíjet n vláken současně, ale budou stejné počty stejných typů b) musí pokračovat v párech tj. danou činnost smí vyvíjet pouze dvě vlákna současně Producent konzument více producentů více konzumentů sdílená paměť buffer konzument odebírá data z paměti k paměti může přistupovat pouze jeden čtení i zápis je exkluzivní Reálně má buffer konečnou kapacitu v případě producent2 ani neznáme aktuální obsazení bufferu pokud je buffer plný, musí producenti čekat na uvolnění pokud je buffer prázdný, musí konzumenti čekat na naplnění mutex = semaphore(1) items = semaphore(0) Producet data = obtaindata() buffer.push(data)
items.signal() Konzument items.wait() data = buffer.pop() processdata(data) Obměna jeden semafor hlídá stav zásobníku Producent data = obtaindata() spaces.wait() buffer.push(data) items.signal() Konzument items.wait() data = buffer.pop() spaces.signal() processdata(data) Čtenáři písaři více konzumentů více producentů konzument neodebírá data z paměti čtení se může provádět souběžně zápis vylučuje čtení a naopak ale od každého může být více instancí kategorické vyloučení Písař roomempty.wait() writedata() roomempty.signal() Čtenář readers = readers + 1 if readers == 1 roomempty.wait() readdata() readers = readers 1 if readers == 0 roomempty.signal()
poslední odejde a zhasne lock() unlock() vzor lightswitch písaři stárnou pokud stále přichází čtenáři, je potřeba zajistit, aby se dostalo i na písaře v algoritmu je implicitně zavedená priorita velmi zrádné není vidět na první pohled Písař turnstile.wait() roomempty.wait() writedata() turnstile.signal() roomempty.signal() Čtenář turnstile.wait() turnstile.signal() readers = readers + 1 if readers == 1 roomempty.wait() readdata() readers = readers 1 if readers == 0 roomempty.signal() CUDA - Compute Unified Device Architecture Platforma pro paralelizované výpočty na GPU Každá shader je jednotka schopná provádět jakýkoliv výpočetní úkol paměti Paměti cuda Registry extrémně rychlé,přístupné jednotlivými vlákny Sdílená paměť extrémně rychlá, vysoce paralelní, dostupná pro jednotlivé bloky Globální paměť dostupná pro všechny, pomalá (400 800 cyklů), nevhodná pro přístup z vláken Konstantní paměť readonly, rychlá odezva a velká propustnost Bloky a vlákna Vlákna jsou sjednocovány do bloků - možnost 1D, 2D, 3D indexace Blok je spouštěn a na mutiprocesoru Bloky čekají ve frontě ke zpracování na dostupných multiprocesorech Bloky vykonávají stejný kernel Identifikace vlákna: interní proměnná threadidx
Mřížka a bloky Bloky vláken jsou sjednocenydo mřížky Každá mřížka (Grid) může spouštět rozdílné kernely Mřížka > Blok > Vlákno Identifikace vlákna ve vícerozměrném bloku : threadidx.x threadidx.y threadidx.z Identifikace bloku: interní proměnná blockidx (blockidx.{x,y}) CUDA příklad Zpracování obrázku 1024 x 1024 px Potřebujeme 1 048 576 vláken Stanovíme rozměr Bloku na 16 x 16 256 vláken Potřebujeme 4096 bloků ((1024x1024) / 256 ) Vytvoříme 2D mřížku (64 x 64 bloků)
CUDA škálování Rozložení stejného výpočtu na různých GPU s různým počtem multiprocesorů automatické MUTEX ochrana kritické sekce Stručně vysvětlete pojem "preemptivní multitasking". Čím je významný pro paralelizaci? - běžící procesy se střídají, operační systém přiděluje procesorový čas běžícím vláknům/procesům, v pravidelných časových intervalech (řádově 100 1000x za vteřinu) uspává/probouzí vlákna. Umožňuje běh více-procesů (vláken) na 1-dno jádrovém CPU Vysvětlete pojem "pipelining". - zřetězení (překrývání) strojových instrukcí, instrukce je rozdělena mezi více částí procesoru -> více instrukcí najednou (minimálně 2 úseky) Vysvetlete pojem "scalability" (škálovatelnost) paralelního systému. -míra růstu výkonosti s růstem paralelismu zefektivnění algoritmu s přidáváním paralelizmu Vysvetlete pojem "uváznutí". Jak muže vzniknout? -tzv deadlock je situace, kdy jedno vlákno čeká na dokončení činnosti jiného vlákna, které čeká na dokončení činnosti vlákna prvního vzájemné zablokování Vysvětlete pojem "atomičnost". Jakým způsobem je možné ji zajistit? - atomická operace se provede celá najednou nebo vůbec. Zajišt uje konzistenci dat. Dosáhneme jí vzájemným vylučením (mutex) Co jsou to "synchronizační pravidla". Uveďte konkrétní příklad. omezení pro koordinaci procesů musí se zajistit přístup ke globálním proměnným (nelze číst a zapisovat zároveň) musí se vyvarovat deadlock musí se vymyslet, synchronizační vzory. Vysvětlete pojem "stárnutí". Jak může vzniknout? Když vlákno čeká na zpracování tak stárne, vzniká u vláken s prioritou, kdy prioritnější vlákno předbíhá méně prioritní. Vysvětlete pojem "synchronizace". koordinace vláken - provádění příkazů v požadovaném pořadí. Kontrolovaný přístup ke sdíleným zdrojům (paměť). Vysvětlete pojem "serializace". zajištění posloupnosti událostí události se provedou sekvenčně, pokud je zaručeno pořadí jejich provedení události se provedou souběžně, pokud se mohou provést ve stejný čas nebo v různém pořadí souběžně se provádí něco, o čem z kódu nedokážeme říct, který řádek se provede dřív Vysvětlete, jakým způsobem se implementují cykly při použití architektury CUDA. na GPU (takže i CUDA) nejsou FOR cykly
Zjistím, kolik je potřeba udělat operací a podle toho vytvořím počet vláken -> bloky -> mřížku, poté každé vlákno vykonává danou operaci Vlákno se identifikuje podle souřadnic, jsou provedena všechna vlákna. K čemu je užitečný Amdahlův zákon? (Jaké jsou pohledy na funkcní závislost Amdahlova zákona? Co z nich lze zjistit?) předpovězení teoretického maximálního zrychlení při přidávání dalších procesorů. f s f p = 1 f s podíl programu, který nelze paralelizovat f p podíl programu, který lze paralelizovat t celková doba výpočtu p počet procesorů t 1 S z = t f s + t f = p p 1 f p + f p p Výkon X počet jader -> objem zlepšení Vysvětlete pojem "kernel" v souvislosti s architekturou CUDA. Je to kód pro GPU, který využívá HW zdroje k provádění operací. Mřížky mohou spouštět rozdílné kernely, ale bloky v rámci 1 mřížky vykonávají stejný kernel. Vysvětlete princip rozkladu a škálování práce na procesory pri použítí architektury CUDA. 1 operace = vlákno organizovaná do bloků > mřížka. Bloky čekají ve frontě ke zpracování na dostupných multiprocesorech -> čím víc multiprocesrů k dispozici tím víc bloků běží paralelně. Rozložení stejného výpočtu na GPU s různým počtem multiprocesorů automatické. Popište systém typu MIMD (pocet výpocetních jednotek (PU), prístup PU k instrukcím a k datum, uveďte príklad reálného systému z této kategorie) Různá PU mohou provádět různé operace - různá PU pracují s jinými daty. Moderní počítače, Distribuované systémy, HW virtualizace Vysvětlete podstatu synchronizačního vzoru "bariéra" a uveďte příklad reálného problému, při jehož řešení se tento vzor použije. Synchronní schůzka pro libovolný počet vláken. Bariéra zajistí, aby vlákna došla do bodu setkání, a všechny je propustí s příchodem vlákna posledního. Například večeře x lidí, řekněme, že se sejdou v restauraci, ale objednají si, až přijde poslední. Vysvětlete pojmy: mřížka, blok, vlákno v souvislosti s GPU architekturou CUDA. V rámci GPU provádí vlákno jednu operaci (spouští kernel), vlákna jsou organizována do bloků (1D, 2D, 3D) a indexovány, v rámci bloku sdílejí paměť. Bloky jsou organizovány do mřížky (o5 1D, 2D, 3D) a indexovány indexem v rámci mřížky Overhead režie paral. systému čas spotřebovaný na komunikaci čas spotřebovaný na synchronizaci a výměnu dat ostatní režie (knihovny, spuštění, zastavení) Rozhodnout zda má smysl paralelizovat algoritmus
Časová složitost výpočtu musí být vyšší než časová složitost komunikace, jinak nemá cenu zpracovávat na dvou procesorech. (1003) Následující pseudokód se snaží implementovat jednoduchou bariéru, která není znovupoužitelná: // Main mutex = Semaphore(1) barrier = Semaphore(0) count = 0 // Thread count = count + 1 if count == num_threads() { barrier.signal() } barrier.wait() Za jakých okolností tento kód bude fungovat? Za jakých okolností tento kód nebude fungovat? Uveďte, jaké chyby se v kódu vyskytují. a. n se musí rovnat počtu vláken, jinak to nebude fungovat b. Pokud alespoň jedno vlákno někde vytuhne, tak nastane deadlock c. Přidal bych mutex na if count == num_threads() ------------------------------- Napište kód, který demonstruje implementaci serializace s využitím semaforu. K čemu je tento kód užitečný? (zdrojový kód můžete psát v lib. jazyce nebo i pseudokódu, jde o synchronizační vzor, nejde o to, aby to šlo spustit). Asi priklad jak semafor pouzit aby 2 vlakna delali něco zaroven, po sobe Napište kód, který demonstruje implementaci producenta a konzumenta s využitím semaforu. K cemu je tento kód užitecný? 2 typy prycovních vláken. Jedno vlákno generuje data, druhé je zpracovává //main Mutex = semaphore (1) items=semaphore(0) buffer = new qeue() //producent data = obtaindata() buffer.push(data) items.signal() mutex.signal
//consument Items.wait() Mutex.wait() Item = data.pop() Mutex.signal() processdata(item) Napište kód, který demonstruje implementaci mutexu s využitím semaforu. K čemu je tento kód užitečný? Vzájemné vyloučení- zamezí přístupu dalším vláknum do kritické sekce v okamžiku, když s ní pracuje některé vlákno Mutex = semaphore(1) //thread Mutex.wait() //critical section Count = count +1 Mutex.signal))