Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

Vývoj vysoce výkonného software

Podobné prezentace


Prezentace na téma: "Vývoj vysoce výkonného software"— Transkript prezentace:

1 Vývoj vysoce výkonného software
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

2 O čem to bude NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

3 Maximální využití výkonu procesoru a paměti
O čem to bude Maximální využití výkonu procesoru a paměti Moderní programování vs. výkon Relevantní vlastnosti moderních procesorů ILP, SIMD Nástroje pro ladění výkonu Co dokáže a co nedokáže překladač Paměťová hierarchie Cache-Aware a Cache-Oblivious algoritmy NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

4 O čem to nebude NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

5 Programování v asembleru
O čem to nebude Programování v asembleru Překladače jsou většinou lepší než lidé Ale naučíme se využívat SIMD instrukce z C++ Paralelní programování Viz NPRG042 Programování v paralelním prostředí Poučení z minulých let: Pečlivá implementace jednovláknové verze přináší stejné zrychlení jako paralelizace Optimalizace programů překladačem Viz NSWI109 Konstrukce překladačů Ale dozvíte se, co můžete od překladače očekávat NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

6 Proč? NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

7 Loňské DÚ 1 (letošní DÚ 2 bez optimalizace) – výsledky studentů
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

8 Loňské DÚ2 (letošní DÚ2 včetně optimalizace) - výsledky studentů
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

9 Motivační příklad NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

10 Motivační příklad - DÚ 0+1
Hromada jablek a pomerančů, spočítejte zrníčka class Apple ... { ... ... int seeds() { return ...; } }; class Orange ... vector< Apple + Orange> data; NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

11 Klasické objektové řešení
Motivační příklad class Fruit { ... virtual int seeds() = 0; }; class Apple : public class Fruit { virtual int seeds() { return ...; } class Orange : public class Fruit { vector< Fruit *> data; Klasické objektové řešení Abstraktní třída s virtuální funkcí Konkrétní třídy Různá data Různé implementace virtuální funkce Kontejner Obsahuje ukazatele na abstraktní třídu Toto řešení existuje ve všech objektových jazycích V jazyzích s referenční semantikou jsou ukazatele skryté List< Fruit> data; NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

12 Motivační příklad Jak je to rychlé? Testovací data
class Fruit { virtual int seeds() = 0; }; class Apple : public class Fruit { virtual int seeds() { return d2; } int d1, d2, d3; class Orange : public class Fruit { virtual int seeds() { return d3; } int d1, d2, d3, d4, d5; vector< Fruit *> data; int s = 0; for_each( data.begin(), data.end(), [&]( Fruit * p) { s += p->seeds(); }); Jak je to rychlé? Testovací data 5 konkrétních tříd lišících se počtem datových položek Implementace virtuální funkce čtou některou z položek Kontejner naplněn náhodnou směsí konkrétních tříd NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

13 Motivační příklad Testovací prostředí Test je opakován N-krát
void test() { int s = 0; for_each( data.begin(), data.end(), [&]( Fruit * p) { s += p->seeds(); }); } generate_data(); test(); // cold run time_before = now(); for ( int i = 0; i < N; ++ i) test(); time_after = now(); cout << (time_after - time_before) / N; Testovací prostředí Test je opakován N-krát N je voleno tak, aby celkový čas byl přiměřený V našem testu sekundy Program si měří čas sám Ve standardu C++ vhodná funkce now() není Plaformy nabízejí různé možnosti Ty lepší jsou pouze pro privilegované V našem testu měříme "wall clock" Je to to, co uživatele zajímá? Zatíženo paralelně běžícími procesy Granularita 1-10 ms NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

14 Výsledky Výsledky testu Hardware Operační systém 64-bitový kód
objektů Celkem 10,4 ms 10,4 ns na objekt 1 000 objektů Celkem 9,0 µs 9,0 ns na objekt Spolehlivost výsledků? Při opakování se výsledky liší o 5-10% Pro orientaci dostatečné Statisticky správné měření je věda NSWI131 Vyhodnocování výkonnosti počítačových systémů Hardware Intel Core2Quad Q6700 2,66 GHz 4 GB RAM Operační systém Windows 7 64-bit 64-bitový kód Překladače MS Visual C MS Visual C Intel Composer XE 2013 Rozdíly menší než 5% NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

15 Výsledky - porovnání architektur na témže HW
64-bitový kód (Intel-64) objektů Celkem 10,4 ms 10,4 ns na objekt 1 000 objektů Celkem 9,0 µs 9,0 ns na objekt Ukazatele jsou delší Procesor vykonává více práce Přesto běží rychleji! Architektura ma víc registrů Procesor je optimalizován pro tento mód Nebo je to jinak... 32-bitový kód (IA-32) objektů Celkem 10,7 ms 10,7 ns na objekt 1 000 objektů Celkem 10,0 µs 10,0 ns na objekt NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

16 Výsledky - závislost na distribuci dat
64-bitový kód (Intel-64) objektů náhodně 10,4 ns na objekt 1 000 objektů náhodně 9,0 ns na objekt objektů round-robin 8,0 ns na objekt 1 000 objektů round-robin 2,6 ns na objekt objektů skupinově 7,6 ns na objekt 1 000 objektů skupinově 2,8 ns na objekt 32-bitový kód (IA-32) objektů náhodně 10,7 ns na objekt 1 000 objektů náhodně 10,0 ns na objekt objektů round-robin 5,9 ns na objekt 1 000 objektů round-robin 2,2 ns na objekt objektů skupinově 5,3 ns na objekt 1 000 objektů skupinově 2,6 ns na objekt NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

17 Příčiny Predikce skoků Volání virtuální funkce je nepřímý skok
Dokud není znám cíl skoku, dekódování instrukcí nemůže pokračovat Procesory předvídají cíle Z předchozích průchodů tímtéž kódem Asociativní paměť adresa skokové instrukce - adresa cíle Heuristické metody predikce Call-return páry Když predikce nevyjde Dekódované a částečně provedené instrukce se zahazují Čeká se na dekódování těch správných Zdržení v řádu jednotek až desítek cyklů procesoru NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

18 Příčiny Predikce skoků Volání virtuální funkce je nepřímý skok
Dokud není znám cíl skoku, dekódování instrukcí nemůže pokračovat Procesory předvídají cíle Z předchozích průchodů tímtéž kódem Asociativní paměť adresa skokové instrukce - adresa cíle Heuristické metody predikce Call-return páry Když predikce nevyjde Dekódované a částečně provedené instrukce se zahazují Čeká se na dekódování těch správných Zdržení v řádu jednotek až desítek cyklů procesoru NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

19 Typické mikroarchitektury procesorů (2000-2012)
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

20 NPRG054 Vývoj vysoce výkonného software - 2013/2014 David Bednárek

21 Intel Netburst Microarchitecture [2000]
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

22 Intel NetBurst Microarchitecture [2000]
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

23 Intel Core Microarchitecture Pipeline [2006]
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

24 Intel Core Microarchitecture
Procesor (teoreticky) zvládá v jediném cyklu najednou: Fetch: 16 B (cca. 4 instrukce) z instrukční cache Decode: 1 až 5 instrukcí ALU: 3 jednodušší operace (add/mul) Memory load: 1 čtení (až 128 bitů) z L1 cache Memory store: 1 zápis (až 128 bitů) z L1 cache Doba trvání operací (latence) integer add, mul: 1 FP add: 3, FP mul: 4-5 div: podle dat integer load: 3, FP load: 4 (L1 cache) store address: 3 store data: 2 (retirement, in-order) NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

25 Intel Core Microarchitecture
Branch prediction podmínky, nepřímé skoky, call/return páry spekulativní provádění Dekodér instrukcí loop cache (jednoduché cykly do 18 instrukcí) převod na mikrooperace 1:1, 1:N, 2:1 simulátor ukazatele zásobníku Renamer 16 logických registrů mapováno do 144 fyzických (podobně FP registry) Out-of-order execution 32 rozpracovaných mikrooperací (RS) z okna délky 96 (ROB) retirement: zápisy do paměti/registrů běží in-order opožděně na pozadí store forwarding: čekající čtení dostávají hodnotu přímo ze zápisu spekulativní čtení: nečeká se na předchozí store NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

26 Intel Nehalem Pipeline [2008]
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

27 Intel Sandy Bridge Pipeline [2011]
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

28 Intel vs. AMD architectures (realworldtech.com)
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

29 Intel Haswell Microarchitecture
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

30 Pohled překladače na procesor
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

31 Scheduling - volba uspořádání instrukcí
Nejpodstatnější fáze překladače z hlediska výkonu kódu Platilo do nedávna, narušeno out-of-order execution v CPU Hledá se takové pořadí které je Ekvivalentní z hlediska efektu/pravidel jazyka Vyhovuje dependencím Nejrychlejší Model časování procesoru NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

32 Závislost (dependence)
Závislosti Závislost (dependence) Povinnost provést jednu operaci/instrukci po jiné Částečné uspořádání operací/instrukcí v jednom BB Datová závislost (dependence) Závislost producent-konzument v toku dat Antidependence Read-Write: Čtení se musí stihnout před zápisem Write-Write: Pořadí zápisů se nesmí změnit Jiné důvody, obvykle nízkoúrovňového původu

33 Scheduling pouze odhaduje skutečné časování
Skutečné časování je ovlivněno nepředvídatelnými jevy Zbytky rozpracovaných instrukcí z předchozího kódu Řešení: Trace-scheduling, řízení profilem Paměťová hierarchie Doba přístupu k paměti závisí na přítomnosti v cache Obvykle se předpokládá nejlepší možný průběh Speciální problém: Multithreaded aplikace na multiprocesorech Fetch bandwidth Instrukce nemusí být načteny a dekódovány včas Zdržují skoky a soupeření o přístup do paměti Přesné simulování fetch jednotky by neúměrně komplikovalo scheduler Scheduler nezná skutečné závislosti přístupů do paměti Musí postupovat opatrně a zohledňuje i nejisté závislosti Procesor zná skutečné adresy přístupů a detekuje pouze skutečné závislosti Agresivně optimalizující procesor může zvolit zcela jiné pořadí instrukcí

34 Scheduling Model procesoru
Latence – časování závislých dvojic instrukcí Počet cyklů procesoru, který musí proběhnout mezi referenčními body závislých instrukcí U antidependencí a ve speciálních případech může být nulová U procesorů se sekvenčními body může být záporná

35 Scheduling Model procesoru
Rezervační tabulky – schopnosti paralelního zpracování Procesor je rozdělen na funkční jednotky různých druhů Je určen počet jednotek každého druhu Pro každou instrukci definována rezervační tabulka Počet jednotek daného druhu, který instrukce potřebuje v daném čase (měřeno od referenčního bodu) Rezervační tabulky jsou nutné i pro procesory, které nejsou super-skalární

36 Scheduling - pokročilé techniky
Loop unrolling V cyklech s malým počtem instrukcí někdy není co paralelizovat Současné zpracování dvou nebo více iterací pomůže Modulo scheduling, software pipelining

37 Příklad – Intel compiler – x64
char chksum( char * p, int i) { char s = 0; while ( i > 0 ) s ^= *p++; --i; } return s; ..B1.4: movsbq (%rdi), %r8 movsbq 1(%rdi), %r9 xorl %r8d, %eax xorl %r9d, %eax addq $2, %rdi addl $1, %ecx cmpl %edx, %ecx jb B1.4 /*...*/ k = i >> 1; j = 0; do { r8 = *p; r9 = *(p+1); s ^= r8; s ^= r9; p += 2; j += 1; } while ( j < k ); /* ... */

38 Průchod polymorfní datové struktury - pohled procesoru
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

39 Kritický kód - Intel C++ 64-bit
Zdrojový kód std::for_each( b, e, [&](Fruit * p){ s += p->seeds(); }); Smyčka po inline expanzi for(; b != e; ++ b) s += (*b)->seeds(); Generovaný strojový kód .lp: mov rcx, QWORD PTR [r14] mov rax, QWORD PTR [rcx] call QWORD PTR [8+rax] add r14, 8 add DWORD PTR [88+rbp], eax cmp r14, r13 jne lp ; Prob 82% Tělo virtuální funkce seeds mov eax, DWORD PTR [8+rcx] ret Registry r14 = b r13 = e rcx = * b rax = VTable eax = hodnota f() rbp = stackframe [88+rbp] = s Skoky dobrá predikce ret jne špatná predikce call NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

40 Kritický kód - Intel C++ 64-bit
Zdrojový kód std::for_each( b, e, [&](Fruit * p){ s += p->seeds(); }); Smyčka po inline expanzi for(; b != e; ++ b) s += (*b)->seeds(); Generovaný strojový kód .lp: mov rcx, QWORD PTR [r14] mov rax, QWORD PTR [rcx] call QWORD PTR [8+rax] add r14, 8 add DWORD PTR [88+rbp], eax cmp r14, r13 jne lp ; Prob 82% Tělo virtuální funkce seeds mov eax, DWORD PTR [8+rcx] ret Závislosti write-read read-write test-access Restart pipeline Špatně predikovaný skok do virtuální funkce NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

41 Kritický kód - Intel C++ 64-bit
Tělo virtuální funkce seeds mov eax, DWORD PTR [8+rcx] ret Konec smyčky add r14, 8 add DWORD PTR [88+rbp], eax cmp r14, r13 jne lp ; Prob 82% Začátek smyčky .lp: mov rcx, QWORD PTR [r14] mov rax, QWORD PTR [rcx] call QWORD PTR [8+rax] Špatně predikovaný cíl volání mov eax, DWORD PTR [4+rcx] Mikrooperace (odhad) load eax,[8+rcx] load t1,[rsp++] jmp t1 add r14,8 load t2,[88+rbp] add t2,eax store [88+rbp],t2 cmp r14,r13,eflags jne .lp,eflags load rcx,[r14] load rax,[rcx] load t3,[8+rax] store [--rsp],rip jmp t3 load eax’,[4+rcx] load t4,[rsp++] jmp t4 NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

42 Odhad provedení kritického kódu s neúspěšnou predikcí
fetch+decode load ALU retire+store 1..3 1 4 2 5..7 3 8..9 10..14 5 1'..3' 6 7 . 2 8 . . 5 9 . . 10 . 10 2..4 11 . 16 12 6..9 13 . 11 14 . 1' 15 16 . 12 17 . 2' 18 19 . 12..14 1: load eax,[8+rcx] 2: load t1,[rsp++] 3: jmp t1 4: add r14,8 5: load t2,[88+rbp] 6: add t2,eax 7: store [88+rbp],t2 8: cmp r14,r13,eflags 9: jne .lp,eflags 10: load rcx,[r14] 11: load rax,[rcx] 12: load t3,[8+rax] 13: store [--rsp],rip 14: jmp t3 1': load eax’,[4+rcx] 2': load t4,[rsp++] 3': jmp t4 NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

43 Odhad provedení kritického kódu s úspěšnou predikcí
fetch+decode load ALU retire+store 1 4 . 2 8 2 . . 5 3 . . 10 . . 2..4 5 . 6 11 6..9 . 1’ 4’ 10 . . 2’ 8’ . .12 . . 5’ . . 10’ .. 12..14 6’ 1’..4’ 7 11’ 5’..8’ . 1’’ 4’’ 9’-10’ . . 2’’ 8’’ . . 12’ . . 5’’ . . 10’’ 1: load eax,[8+rcx] 2: load t1,[rsp++] 3: jmp t1 4: add r14,8 5: load t2,[88+rbp] 6: add t2,eax 7: store [88+rbp],t2 8: cmp r14,r13,eflags 9: jne .lp,eflags 10: load rcx,[r14] 11: load rax,[rcx] 12: load t3,[8+rax] 13: store [--rsp],rip 14: jmp t3 NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

44 Výsledky (Intel Core Microarchitecture, 2.66 GHz)
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

45 Náhodně promíchané objekty
Hodnocení výsledků Náhodně promíchané objekty Neúspěšná predikce skoku Zpoždění načítání instrukcí + zátěž spekulativně provedenými instrukcemi Odhad 20 cyklů = 7.5 ns, měření 9-13 ns (cache misses) Objekty uspořádané do skupin podle druhu Zlepšuje predikci skoků U malých dat neúčinné – procesor se nestíhá naučit Zůstává režie nepřímého volání (ověření predikce) - zatěžuje procesor Odhad 8 cyklů = 3 ns, měření 3-8 ns (cache misses) NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

46 Jiný přístup Bez dědičnosti Bez ukazatelů Volání nebudou nepřímá
class Apple { int seeds() { return d2; } int d1, d2, d3; }; class Orange { int seeds() { return d3; } int d1, d2, d3, d4, d5; vector< Apple> dataA; vector< Orange> dataO; int s = 0; for_each( dataA.begin(), dataA.end(), [&]( Apple & x) { s += x.seeds(); }); for_each( dataO.begin(), dataO.end(), [&]( Orange & x) { s += x.seeds(); }); Bez dědičnosti Volání nebudou nepřímá Překladač volané funkce integruje Odpadá režie volání Dovoluje další optimalizace Bez ukazatelů Ušetříme 1 přístup do paměti Data jsou těsně vedle sebe Nulová režie Hardware prefetch Použitelné pro operace nezávislé na pořadí Pro udržení pořadí je zapotřebí další struktura Pro operace závislé na pořadí neušetříme NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

47 Výsledky (Intel Core Microarchitecture, 2.66 GHz)
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

48 Sloupcově orientovaný přístup
vector< int> Ad1, Ad2, Ad3; vector< int> Od1, Od2, Od3, Od4, Od5; int s = 0; for_each( Ad2.begin(), Ad2.end(), [&]( int x) { s += x; }); for_each( Od3.begin(), Od3.end(), Uložení po sloupcích Umožňuje použití SIMD instrukcí Čtená data jsou těsně vedle sebe Lepší využití cache Nevýhody Ignoruje výhody objektového programování (enkapsulace) Data jednoho objektu jsou rozptýlena Horší využití cache při náhodném přístupu Moderní databázové stroje používají sloupcový přístup NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

49 Sloupcově orientovaný přístup
vector< int> Ad1, Ad2, Ad3; vector< int> Od1, Od2, Od3, Od4, Od5; int s = 0; for_each( Ad2.begin(), Ad2.end(), [&]( int x) { s += x; }); for_each( Od3.begin(), Od3.end(), SIMD instrukce Intel/AMD: MMX/SSE/AVX/... Některé překladače je dokážou vygenerovat samy Jinde existují knihovní funkce skrývající SIMD instrukce Použití vyžaduje znalost těchto instrukcí Problém: zarovnání Data pro SIMD instrukci se načítají obvykle atomicky Vyžadují zarovnání větší než obvykle (SSE: 16 B) Problém: nedělitelné zbytky na koncích polí Zvýšená režie cyklu SIMD se nevyplatí pro malá pole NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

50 Sloupcově orientovaný přístup – SSE3
#include <emmintrin.h> vector< __m128i> Ad1, Ad2, Ad3; std::size_t reserve; __m128i ss = 0; for_each( Ad2.begin(), Ad2.end() - 1, [&]( __m128i & x) { ss = _mm_add_epi32( ss, x); }); int s = ss.m128i_i32[ 0] + ss.m128i_i32[ 1] + ss.m128i_i32[ 2] + ss.m128i_i32[ 3]; for_each( Ad2.back().m128i_i32, Ad2.back().m128i_i reserve, [&]( int x) { s += x; }); Microsoft VC++/Intel C++ Knihovní funkce skrývající SIMD instrukce Baleny jednotlivě Překladač je zná a integruje Překladač sám přiděluje registry Použití vyžaduje znalost těchto instrukcí jednodušší než programování v assembleru __m128i je 128-bitový typ odpovídající SSE registru Překladač (někdy) zajistí zarovnání _mm_add_epi32 odpovídá SIMD instrukci PADDQ 4-krát součet 32-bitových čísel NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

51 Výsledky (Intel Core Microarchitecture, 2.66 GHz)
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

52 Výsledky (Intel Core Microarchitecture, 2.66 GHz)
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

53 Uspořádání objektů podle typu Oddělení skladování objektů různých typů
Shrnutí Uspořádání objektů podle typu Zrychlení 2 až 4-krát proti náhodně uspořádanému průchodu Oddělení skladování objektů různých typů Zrychlení 4 až 8-krát proti společnému uspořádánému seznamu Navíc šetří paměť (odpadá režie dynamické alokace) Uložení po sloupcích a použití SIMD instrukcí Zrychlení 3-krát proti oddělenému skladování Celkové zrychlení 20 až 60-krát Jde o dobře zvolenou jednoduchou úlohu V reálnějších případech to tak dramatické nebude Vše je podmíněno možností změnit pořadí průchodu NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

54 Nástroje na ladění výkonu
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

55 Techniky ladění výkonu
Optimalizovat celý program je zbytečná práce Pravidlo 90:10 nebo dokonce 99:1 Cíl 1: Identifikovat hotspot Místo v kódu, ve kterém program tráví významnou část celkového času Z logického pohledu hotspot zahrnuje i procedury z něj volané Při této definici je však největším hotspotem main Jiný pohled: hotspot je kód, který se provádí mnohokrát To ale nemusí znamenat, že se v něm tráví významný čas Další možnost: hledat kód, který má problém Např. mnoho času na jednu instrukci Z tohoto pohledu ubrání instrukcí vytváří problém Realistický přístup: Neumíme to definovat, ale poznáme to Programátor má představu, co by mělo být hotspotem Měření může ukázat, že představa byla špatná Cíl 2: Zjistit, co zdržuje provádění hotspotu Detekce/počítání/lokalizace zdržujících událostí NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

56 Techniky měření chování programu
Instrumentace Úprava programu tak, aby se sám změřil Provádí překladač na mezikódu nebo zvláštní nástroj na binárním kódu Měřicí kód významně narušuje běh programu Má smysl měřit pouze neovlivněné veličiny Profil: počet průchodů jednotlivými místy v programu Základní bloky (přechody mezi nimi) Procedury Procedury včetně vzájemných volání Optimalizace řízené profilem Překladač využívá dříve naměřený profil při určení, které části programu optimalizovat při výpočtu ceny u některých optimalizací NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

57 Techniky měření chování programu
Sampling Pouští se nemodifikovaný program Ve vhodně vybraných okamžicích se zjistí aktuální pozice IP IP včetně volajících procedur (dešifrování návratových adres ze zásobníku) Četnost pozic v celkovém seznamu vzorků určuje hotspoty Okamžiky samplování musí být Dostatečně řídké, aby neovlivňovaly běh programu Dostatečně husté, aby produkovaly statisticky významná data Známým způsobem korelované s během programu Nezávislé - náhodný sampling (aproximace: periodický sampling) Závislé na vybraných událostech (počet provedených instrukcí, přístupů do paměti apod.) NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

58 Techniky měření chování programu
Sampling Techniky generování událostí Softwarové - přerušení časovačem Vyžaduje častější přerušení než obvyklé nastavení časovače v OS Periodické přerušování nemusí být statisticky nezávislé na běhu programu Hardwarové - podpora v procesoru Procesor generuje interní přerušení po dosažení nastaveného počtu událostí Hodinový signál, instrukce, přístupy do paměti, mispredikce, ... Techniky záznamu vzorku Softwarové - záznam vytváří obsluha přerušení Hardwarové - záznam vytváří procesor zápisem do paměti Dovoluje častější vzorkování Nedovoluje zkoumání zásobníku Nedovoluje randomizaci vzorkovací periody NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

59 Paměťová hierarchie NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

60 Současné technologie polovodičových pamětí
Statická RAM Dynamická RAM Flash EPROM Princip záznamu Elektrický obvod se dvěma stabilními stavy Nabitý kondenzátor Výdrž záznamu Po dobu napájení Desítky milisekund Desítky let Princip čtení Měření napětí na výstupu obvodu Vybití kondenzátoru Ovlivnění vodivosti elektrickým polem kondenzátoru Princip zápisu Změna napětí vstupů obvodu Nabití kondenzátoru Nabití/vybití kondenzátoru tunelováním Tranzistorů na bit 6 1 1/3 Moorův zákon – dvojnásobná kapacita 2 roky 1,5 roku 1,4 roku Latence 0.5-5 ns dle velikosti 20-30 ns dle architektury Moorův zákon – poloviční latence ? 7 let NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

61 Dynamická RAM NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

62 Architektura paměti DRAM
Otevření řádku Adresa řádku se dekóduje Hodnota řádku se přenese do řádkového bufferu Čtení/zápis Adresa sloupce se dekóduje Bit v řádkovém bufferu se přečte/nastaví Zavření řádku Hodnota z řádkového bufferu se zapíše do řádku řádkový dekodér matice kondenzátorů řádkový buffer sloupcový dekodér adresa řádku adresa sloupce data NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

63 Architektura paměti DRAM
Typické rozměry 16384 řádků 8192 sloupců celkem 128 Mbit Typické časy tRCD = 13 ns Otevření řádku tCL = 13 ns Čtení/zápis tRP = 13 ns Zavření řádku řádkový dekodér 1:16384 matice kondenzátorů řádkový buffer 8192 bit sloupcový dekodér 32:8192 adresa řádku 14 bit adresa sloupce 8 bit data 32 bit NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

64 Architektura paměti DRAM – příklad čipu
banka 0 banka 1 banka 2 banka 3 banka 4 banka 5 banka 6 banka 7 Typický čip matice 128 Mbit 8 bank celkem 1 Gbit 256 M * 4 bit Paralelismus Banky mohou pracovat nezávisle V okamžiku předávání příkazu, adresy nebo dat je připojena jen jedna Synchronizováno hodinovým signálem – programované zpoždění mezi příkazy a daty Časový multiplex dat 8:1 dekodér banky 1:8 data 32 bit multiplexor 8*4:32 adresa banky 3 bit řídící signály adresa 14 bit data 4 bit NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

65 Architektura paměti DRAM - příklad
čip 3 čip 2 čip 1 čip 0 adresy a řízení data 64 bit Rank čip 256 M * 4 bit 16 čipů celkem 2 GB 256 M * 64 bit Paralelismus Všechny čipy dělají totéž Každý řeší 4 bity Doplňky ECC: +2 čipy – paritní kontrola čip 7 čip 6 čip 5 čip 4 čip 11 čip 10 čip 9 čip 8 čip 15 čip 14 čip 13 čip 12 NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

66 Architektura paměti DRAM – typický 4GB DDR3 modul
výběr ranku adresy a řízení data 64 bit DDR3 modul dual rank každý rank 256 M * 64 bit celkem 4 GB 32 čipů 512 M * 64 bit Paralelismus Ranky pracují nezávisle Ke sběrnici může přistupovat jen jeden Doplňky „registered“: opakovač signálů rank 0 rank 1 NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

67 Architektura paměti DRAM - kanály
výběr ranku adresy a řízení data 64 bit DDR3 kanál dva paralelně propojené moduly každý modul 512 M * 64 bit celkem 8 GB 1 G * 64 bit Paralelismus Jednotlivé ranky obou modulů pracují nezávisle Data přenáší pouze jeden Varianty „registered“: až 4 moduly větší a pomalejší modul 0 rank 0 rank 1 modul 1 rank 2 rank 3 NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

68 Architektura paměti DRAM – dual channel
kanál 0 kanál 1 Dual channel 2 kanály každý kanál 1 G * 64 bit celkem 16 GB 1 G * 128 bit nebo 2 G * 64 bit Paralelismus Kanály dělají totéž nebo Kanály pracují a přenášejí data nezávisle rank 0 rank 1 modul 0 rank 2 rank 3 modul 1 rank 0 rank 1 modul 2 rank 2 rank 3 modul 3 NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

69 Architektura paměti DRAM – Příklad: 4 * DDR3 4 GB DR x4
Shrnutí 2 kanály 2*2 = 4 ranky nezávislá činnost 16 čipů shodná činnost 8 bank nezávislá činnost 16384 řádků jeden aktivní 8192 sloupců 32 vybraných NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

70 Architektura paměti DRAM
Atomická operace časový multiplex: 8 přenosů po 64 bitech celkem 512 bitů při 1600 MT/s zaměstná 1 kanál na 5 ns latence 26 ns, s úklidem 52 ns Paralelismus Zbývajících 31 bank kanálu může dělat něco jiného Propustnost kanálu stačí na 200 M operací/s Kanály jsou dva (až 4) NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

71 Rozhraní procesor - DRAM
Přímé připojení na DDR3 1-4 kanály po 64 bitech, každý až 1600 MT/s = 12.8 GB/s Intel DMI, QPI, AMD HyperTransport Serio-paralelní rozhraní, různé šířky, až 25.6 GB/s Intel FSB 1 kanál, 64 bitů, až 1600 MT/s = 12.8 GB/s Komplikovanost rozhraní procesor – DRAM prodlužuje latenci celkem řádově 50 ns, samotná DRAM typicky 25 ns NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

72 Statická RAM NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

73 Architektura paměti SRAM
Řádky a sloupce Aktivace probíhá současně Čtení Celý řádek vysílá své hodnoty Sloupcový dekodér vybírá data Zápis Sloupcový dekodér posílá signály „zapiš 0“ a „zapiš 1“ do vybraných sloupců řádkový dekodér matice klopných obvodů sloupcový dekodér adresa řádku adresa sloupce data NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

74 Architektura paměti SRAM
Banky Velké paměti jsou děleny na banky Paralelismus Operace v různých bankách se mohou překrývat V jednom cyklu lze zahájit pouze jednu operaci Společné sběrnice a dekodér banky brání plnému paralelismu adresa banky adresa řádku a sloupce data NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

75 Architektura paměti SRAM
Dvoubránová paměť V každé buňce je zdvojeno její vnější rozhraní cca 33% plochy navíc Přístup ze dvou bran je zcela nezávislý Současný zápis různých hodnot do téže buňky je nežádoucí Používá se pro malé výkonově kritické paměti registry, TLB NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

76 Asociativní paměť NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

77 Plně asociativní paměť
Každý řádek má svůj komparátor Vyžaduje strategii výměny při zaplnění Drahá nejvýše desítky řádků TLB1 tag data = = = = = = = = tag data NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

78 Přímo mapovaná asociativní paměť
Základem běžná paměť (SRAM) Společný komparátor Nevyžaduje strategii výměny při zaplnění Umožňuje číst data ještě před dokončením porovnání Prakticky nepoužitelná Kolize jsou v reálných aplikacích příliš pravděpodobné SRAM = data index tag NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

79 N-cestně asociativní paměť
Přímo mapovaná asociativní paměť je použita N-krát Vyžaduje strategii výměny při zaplnění Převládající způsob implementace cache N mírně roste s velikostí cache SRAM = SRAM = SRAM = data index tag NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

80 Cache poslední úrovně LLC = L2 nebo L3 Paralelismus
Obvykle společná pro všechna/některá jádra na čipu Typické velikosti 4-16 MB Stupeň asociativity 8-16 Cache Line = 512, někdy 1024 bitů Obvykle odpovídá velikosti atomické operace DDR3 DRAM Latence kolem 10 ns Komunikace LLC – DRAM – vždy celá Cache Line Komunikace s nižšími úrovněmi – obvykle 128 nebo 256 bitů najednou Paralelismus Celý proces přístupu do cache je pipeline lze zahájit 1 přístup každé 1-3 cykly procesoru Cache může být dělena na banky přístup do různých bank může být paralelní NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

81 Cache prostřední úrovně
L2 v systémech s L3 Každé jádro mívá vlastní Typické velikosti 256 KB - 4 MB Cache Line téměř vždy 512 bitů Latence 5-10 ns Komunikace s okolními úrovněmi – obvykle 128 nebo 256 bitů najednou NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

82 Cache první úrovně L1D Paralelismus
Pouze pro data (instrukce mají vlastní L1I cache) Každé jádro má vlastní Systém musí řešit přístup k datům v L1 cache sousedního jádra Typické velikosti KB Cache Line téměř vždy 512 bitů Latence 1-2 ns Komunikace s vyšší úrovní – obvykle 128 nebo 256 bitů najednou Komunikace s jádrem – podle šířky operandu instrukce (8 až 128 bitů) Paralelismus Celý proces přístupu do cache je pipeline v každém cyklu může začít nový přístup Cache může mít více bran v každém cyklu mohou začít dva přístupy, pokud vedou na jiné adresy komunikace s vyšší úrovní běží na pozadí (eject, prefetch) NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

83 Překlad virtuálních adres na fyzické
TLB Překlad virtuálních adres na fyzické Často dvě úrovně TLB DTLB1 pouze pro data, záznamů odpovídá KB adresového prostoru TLB2 společná, cca. 512 záznamů Latence DTLB1 bývá započtena do latence L1D L1D bývá „virtually-indexed-physically-tagged“ Latence TLB2 v řádu 2-3 ns Není-li záznam v TLB: „page walk“ - procesor realizuje 2-4 přístupy do paměti (cache) „page fault“ – řeší operační systém Paralelismus TLB bývá vícebránová – obsluhuje čtení i zápisy paralelně Virtually-indexed cache L1 cache indexována virtuální adresou (nebo ofsetem uvnitř stránky) Překlad v TLB může běžet paralelně s adresací L1 cache Vyžaduje speciální opatření pro případ násobného mapování téže fyzické adresy NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

84 Typické použití bitů adresy (Intel Sandy Bridge)
47-40 39-24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 virtuální adresa DTLB1 tag index assoc TLB2 fyzická adresa L1D L2 L3 velikost 256 TB 1 TB 16 MB 1 MB 64 KB 4 KB 64 B NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

85 Typická latence a propustnost – Intel Sandy Bridge
ALU latence (cykly) operací/ cyklus B/operace B/cyklus GB/s [3 GHz CPU] registry 0 (započteno v čase instrukce) teoreticky 14, prakticky 3-6 4-16 až 112 SIMD až 160 teoreticky 480 L1D 4 3 (2*R+1*W) 12-48 36-144 L2 12 1 32 96 L3 26-31 DDR3-1600 dual channel cca 120 2/15 64 8.5 25.6 reg L1 L2 L3 DRAM NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

86 Typická latence a propustnost – Intel Sandy Bridge
ALU Quad Core ALU ALU ALU reg L1 L2 L3 DRAM NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

87 Důsledky pro programování
Velikosti, latence a architektury cache jsou různé Spolehlivě lze odhadnout pouze dolní mez L1 (16KB) Ladit software na přesné velikosti všech úrovní je téměř nerealizovatelné autotuning, NUMA awareness cache-oblivious algoritmy Velikost Cache Line lze odhadnout spolehlivě – 64B Přesunovat do procesoru méně než 64B je plýtvání spojové seznamy či stromy s malými uzly jsou neefektivní Velikost TLB1 je velmi malá Přístup na větší počet míst paměti je problematický pro TLB, ne pro L1 L1 udrží stovky živých míst, TLB pouze desítky Bucket-sort nebo merge může být TLB-bound více než 64 živých bodů vzdálených od sebe více než 4 KB Bloky dynamicky alokovaných dat mohou být velmi vzdálené 100-prvkový vyhledávací strom se nemusí vejít do DTLB1 NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

88 Nešikovně naprogramovaný kód může dobrý překladač napravit Nevhodnou datovou strukturu překladač nenapraví (a nepomůže ani naprogramování v asembleru) NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

89 Registry poskytují cache úrovně 0
Úrovně cache Registry poskytují cache úrovně 0 Použítí této „cache“ řídí překladač Programátor může vytvořit šanci nebo zlepšit podmínky úpravou kódu Velikost řádky je velikost registru (podle řešené úlohy; SIMD: 128/256 bit) Velikost “L0-cache” dána počtem registrů (Intel: 8/16, některé obsazené) 32 až 512 B Pro danou úlohu a platformu programátor dokáže určit Lze programovat na míru (týká se jádra algoritmu) Velikost řádku Cache je stabilní - 64B Lze programovat na míru (týká se zejména datových struktur) V intervalu 4KB-16MB leží mnoho hranic důležitých velikostí Bez znalosti konkrétní varianty CPU nelze určit přesnou polohu hranic Každé zdvojnásobení velikosti úlohy může dramaticky změnit poměry Nejvhodnější je přístup převzatý z Cache-Oblivious algoritmů Rekurzivní dělení úlohy na části NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

90 Cache-oblivious algorithms
NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

91 Cache-oblivious algorithms
Cache-awareness Algoritmus je vyladěn pro konkrétní parametry cache Prakticky obtížně proveditelné - parametrů je příliš mnoho Cache-obliviousness Víme, že cache existuje, ale neznáme její parametry Cache-oblivious algorithms Pohled na složitost algoritmů zohledňující existenci cache Algoritmy fungující z tohoto pohledu dobře NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

92 Cache-oblivious algorithms (zjednodušený pohled)
Pohled na složitost algoritmů zohledňující existenci cache Počítáme přístupy k hlavní paměti (cache misses) Složitost je funkcí velikosti vstupu (n) a velikosti cache (C) Zjednodušeno (parametrem bývá i velikost cache line) Zkoumá se obvykle asymptotické chování O(f(n,C)) Pro většinu algoritmů je asymptotické chování úměrné časové složitosti (t(n)) O(f(n,C)) = O(t(n)*g(C)) g(C) říká, jak často algoritmus generuje cache miss obvykle g(C) < 1 a klesá s velikostí C Příklad: Násobení matic (n*n) Učebnicový algoritmus (i-j-k iterace) Pro n2>C každý přístup (k pravému operandu) generuje cache miss O(n3) - nezávisí na C; g(C) = 1 Cache-oblivious algoritmus (rekurzivní dělení) O(C-1/2 *n3) tj. g(C) = C-1/2 NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

93 Cache-oblivious algorithms
Pohled na složitost algoritmů zohledňující existenci cache Počítáme přístupy k hlavní paměti (cache misses) Předpokládáme pouze 1 úroveň cache Který algoritmus je lepší? Minimalizujeme g(C) pro všechna C (nikoliv asymptotické chování) To není jednoznačné zadání, ale porovnání obvyklých g jednoznačné bývá (např. C-1/2 < 1) Dobré chování pro cache jakékoliv velikosti implikuje dobré chování pro více úrovní Stále jde o asymptotický pohled vzhledem k n Zanedbáváme multiplikativní konstanty, neřešíme rozdíl čtení/zápis Pro reálné problémy může být výhodnější asymptoticky horší algoritmus Práce s pamětí nemusí být kritické místo algoritmu Zanedbané konstanty často výrazně zkreslují chování pro malá C Jádro algoritmu bývá vhodnější implementovat s přibližnou znalostí chování L1 cache Překladač obvykle neumí sám využít registry jako L0 cache Jako inspirace se vždy vyplatí NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

94 Cache-oblivious algorithms
Rozděl a panuj Problém P0 se dělí na podproblémy P1 a P2 Pamětová složitost: m0 < m1 + m2 Část dat D12 je používána oběma podproblémy: |D12| = d12 = m1 + m2 - m0 Pro m0 > C se problém P0 do cache nevejde Část dat D12 pravděpodobně bude čtena pro P2 znovu z hlavní paměti Počítání přístupů do hlavní paměti (výpadků cache) Každý podproblém musí alespoň jednou načíst/zapsat svá data První přístup nebudeme počítat Vrstva P0 přispěje druhým čtením D12 o velikosti d12 NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

95 Násobení matic - rozděl a panuj
C = A * B, velikosti A[i,k], B[k,j], C[i,j] i-split - dělení problému v dimenzi i i0 = i1 + i2 ; j0 = j1 = j2 ; k0 = k1 = k2 Matice A a C se dělí napůl - podproblémy jsou na nich disjunktní Matice B se nedělí - oba podproblémy ji používají celou: d12 = k0 * j0 Matice B se pro velká data čte z hlavní paměti opakovaně j-split a k-split - další možnosti dělení Jiný příspěvek d12 a jiné rozměry podúloh Končíme u velikosti m0 = i0*k0 + j0*k0 + i0*j0 < C Pod touto velikostí je z hlediska opakovaných výpadků cache cena 0 NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

96 Cache-oblivious algorithms
Normalizace Časová složitost: t0 = t1 + t2 Počítáme g(C) počet (druhých a dalších) přístupů do hlavní paměti na jednotku času g0 (C) = d12/t0 + g1(C) * t1/t0 + g2(C) * t2/t0 pro m0 > C g0 (C) = 0 pro m0 < C Násobení matic - i-split i0 = i1 + i2 ; j0 = j1 = j2 ; k0 = k1 = k2 d12 = k0 * j0 Časová složitost t0 = i0*j0*k0 ; t1 = i1*j0*k0 ; t2 = i2*j0*k0 Normalizovaný počet opakovaných přístupů k hlavní paměti g0 (C) = 1/i0 + g1(C) * i1/i0 + g2(C) * i2/i0 Při dělení napůl i1 = i2 ; g1(C) = g2(C) g0 (C) = 1/i0 + g1(C) NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

97 Násobení matic - rozděl a panuj
Rekurzivní kroky i-split: gi,j,k (C) = 1/i + g i/2,j,k(C) j-split: gi,j,k (C) = 1/j + g i,j/2,k(C) k-split: gi,j,k (C) = 1/k + g i,j,k/2(C) Končíme u velikosti iF*kF + jF*kF + iF*jF < C Rozhoduje součin dvou největších rozměrů Pro dané počáteční <iS;jS;kS> a zvolené koncové <iF;jF;kF> Cena rekurzivního sestupu nezávisí na cestě: gS(C) = 1/iS /iF + 1/jS /2jF + 1/kS /2kF 1/2iF + 1/2jF + 1/2kF < gS(C) < 1/iF + 1/jF + 1/kF Nejlevnější je sestup do koncového bodu se shodnými dvěma největšími rozměry Nejmenší rozměr koncového bodu má být co největší Nejlepší koncový bod pro iS > jS > kS iF = jF = kF = C1/2 pro kS > C1/2 ; cena gS(C) = O(C-1/2) iF = jF = C1/2 ; kF = kS pro jS > C1/2 > kS ; cena gS(C) = O(C-1/2) iF = C / js ; jF = jS ; kF = kS pro iS > C1/2 > jS ; cena gS(C) = O(js /C) iF = is ; jF = jS ; kF = kS pro C > iS * jS ; cena gS(C) = 0 NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

98 Násobení matic - cache-aware
Nejlepší koncový bod pro iS > jS > kS iF = jF = kF = C1/2 pro kS > C1/2 ; cena gS(C) = O(C-1/2) iF = jF = C1/2 ; kF = kS pro jS > C1/2 > kS ; cena gS(C) = O(C-1/2) iF = C / js ; jF = jS ; kF = kS pro iS > C1/2 > jS ; cena gS(C) = O(js /C) iF = is ; jF = jS ; kF = kS pro C > iS * jS ; cena gS(C) = 0 Cache-aware algoritmus - pokud známe velikost cache C Zvolíme koncový bod (objem dat spolehlivě pod velikostí C) Ke koncovému bodu sestoupíme iterací přes ty rozměry, které přesahují C1/2 Iterace odpovídá několika sestupům stejným druhem splitu Režie rekurze je větší než režie iterace Na pořadí vzájemného vnoření iterací teoreticky nezáleží Prakticky na vnoření záleží (cache line, prefetch, čtení/zápisy,...) Předpokládaná normalizovaná cena gS(C) = O(C-1/2) nebo menší 32 KB L1 cache & 8 B double: C = 4096; C-1/2 = 1/64 "jeden" (O(1)) přístup k L2 cache na 64 ALU operací NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

99 Násobení matic - cache-oblivious
Nejlepší koncový bod pro iS > jS > kS iF = jF = kF = C1/2 pro kS > C1/2 ; cena gS(C) = O(C-1/2) iF = jF = C1/2 ; kF = kS pro jS > C1/2 > kS ; cena gS(C) = O(C-1/2) iF = C / js ; jF = jS ; kF = kS pro iS > C1/2 > jS ; cena gS(C) = O(js /C) iF = is ; jF = jS ; kF = kS pro C > iS * jS ; cena gS(C) = 0 Cache-oblivious algoritmus - připravenost na libovolné C Split se provádí v rozměru, který je největší Nejprve dosáhne stavu, kdy jsou dva větší rozměry shodné Následuje střídání splitů v těchto dvou rozměrech Po dosažení shody všech rozměrů střídání všech tří splitů Strassenova algebraická finta: Místo tří splitů dělení na 7 podúloh Celkový počet výpadků cache je O(C-1/2 *i*j*k) NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

100 Cache-oblivious algorithms – vliv bloků
Zjednodušená složitost uvažuje pouze velikost cache C Výsledek nezávisí na způsobu uložení dat v pamětí Úplná cache-aware složitost uvažuje i velikost bloku B Blokem je řádka cache případně stránka vzhledem k TLB f(C,B) Počítají se přesuny bloků mezi cache a hlavní pamětí Lepší paměťová struktura jich spotřebuje méně NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

101 Cache-oblivious algorithms – vliv bloků
Příklad: Násobení matic (n*n) Učebnicový algoritmus (i-j-k iterace), uložení po řádcích Pro n>C každý přístup (k pravému operandu) generuje cache miss f(C,B) = O(n3) - nezávisí na C; g(C) = 1 Při uložení po sloupcích zdržuje přístup k levému operandu Při uložení po čtvercích B1/2 * B1/2 se složitost zlepší na O(B-1/2 * n3) Cache-oblivious algoritmus (rekurzivní dělení, rekurzivní uložení) O(C-1/2 *B-1*n3) tj. g(C) = C-1/2*B-1 Typické hodnoty konstant (neřešíme společnou multiplikativní konstantu) 8 registrů, double: C = 8, B = 1, g(C) = 1/2.8, jednotková cena 1/3 cyklu CPU 8 SSE registrů, double: C = 16, B = 2, g(C) = 1/8 32KB L1 cache, double: C = 4K, B = 8, g(C) = 1/512, jednotková cena 1 cyklus CPU 64-entry TLB, double: C = 64, B = 512, g(C) = 1/4K 8MB L3 cache, double: C = 1M, B = 8, g(C) = 1/8K, jednotková cena 8 cyklů CPU 8 GB RAM, 64 KB blok, double: C = 1G, B = 8K, g(C) = 1/256M, jednotka 300K cyklů (SSD) 512 GB SSD, 64 KB blok, double: C = 64G, B = 8K, g(C) = 1/4G, jednotka cca 2M cyklů (HDD) NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

102 Ideální algoritmus Celková architektura „ideálního algoritmu“
Jádro úlohy pracující v registrech (podúloha velikosti B) Pouze lokální proměnné, pokud možno žádné pole Proměnné čteny z paměti na začátku/zapisovány do paměti na konci V ideálním případě SIMD instrukce Podúlohy do velikosti 8-16KB Data se vejdou do L1 Data podúlohy mohou být v paměti mírně nesouvislá Každý blok násobkem 64 B (cache line) Jsou-li bloky vzdálenější než 4 KB, pak nejvýše 32 bloků (TLB1) Podúloha řešena iterativně nad jádrem úlohy Rekurzivní řešení mívá příliš velký overhead Iterace umožňuje prefetch Úlohy větší než 16 KB Řešeny rekurzivně metodami Cache-Oblivious algoritmů Obvykle se dělí na dvě podúlohy o polovičním počtu operací Každá podúloha má větší než poloviční spotřebu paměti Vybírá se takový způsob dělení, který minimalizuje paměťový překryv podůloh Okolo 16 KB se rekurze nahradí iterací podúlohy Data každé podúlohy by měla mít malý počet bloků (problém TLB) NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

103 Jiný pohled na cache NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

104 Přístupy do paměti v algoritmech jsou dvou druhů
Algoritmy a cache Přístupy do paměti v algoritmech jsou dvou druhů S předvídatelnou adresou Lineární průchody polem for ( i = 0; i < N; ++ i ) { /*...*/ a[ i] /*...*/ } Lineární průchody s větším skokem for ( j = 0; j < M; ++ j ) for ( i = 0; i < N; ++ i ) { /*...*/ a[ i][ j] /*...*/ } S "náhodnou" adresou Hashovací tabulky for ( i = 0; i < N; ++ i ) { /*...*/ a[ hash( d[ i])] /*...*/ } Bucket-sort for ( i = 0; i < N; ++ i ) { /*...*/ a[ b[ i]] /*...*/ } Binární vyhledávání while ( /*...*/ ) { if ( a[ j] > /*...*/ ) j = /*...*/; else j = /*...*/; } Spojové struktury while ( p != 0 ) { /*...*/ p = p->next; /*...*/ } NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

105 Přístupy s předvídatelnou adresou
Algoritmy a cache Přístupy s předvídatelnou adresou Efekt řádku cache: Husté lineární průchody mají dobré hit ratio Write buffers: Zápisy obvykle nezdržují Hardware prefetching procesor detekuje lineární průchody a načítá data do L1 předem Software prefetching překladač generuje instrukce pro přístup k datům předem běžné instrukce pro čtení - vyžadují jistotu příští iterace speciální instrukce pro spekulativní čtení - potlačené výjimky totéž může udělat programátor ručně u dnešních procesorů/překladačů nebývá zapotřebí Latence přístupu se skryje paralelním vykonáváním jiné užitečné činnosti Rozhoduje prostupnost sběrnic paměť-cache-ALU (bandwidth) Algoritmy se optimalizují na nejlepší využití dané prostupnosti NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

106 Přístupy s "náhodnou" adresou
Algoritmy a cache Přístupy s "náhodnou" adresou Adresa nezávislá na předchozí iteraci Latenci přístupu lze skrýt paralelizací Někdy to dokáže sám překladač Hashovací tabulky for ( i = 0; i < N-1; ++ i ) { x = hash( d[ i+1]); /*...*/ v /*...*/; v = a[ x]; } Bucket-sort for ( i = 0; i < N; i += 2 ) { /*...*/ a[ b[ i]] /*...*/ a[ b[ i+1]] /*...*/ } Adresa závislá na předchozí iteraci (loop-carried dependence) Paralelizovat není s čím Rozhoduje latence přístupu Binární vyhledávání while ( /*...*/ ) { if ( a[ j] > /*...*/ ) j = /*...*/; else j = /*...*/; } Spojové struktury while ( p != 0 ) { /*...*/ p = p->next; /*...*/ } NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

107 Adresa závislá na předchozí iteraci (loop-carried dependence)
Algoritmy a cache Adresa závislá na předchozí iteraci (loop-carried dependence) Paralelizovat není s čím Vyžaduje globální úpravu algoritmu (změny rozhraní funkcí) Výměna vzájemné vnořenosti cyklů loop reversal; obecněji afinní transformace cyklů (loop skewing) Vyžaduje stabilní počet iterací vnitřního cyklu Binární vyhledávání for ( i = 0; i < N; ++ i ) bsearch( a, M, b[ i]); upraveno na bsearch_many( a, M, b, N); U nevhodných datových struktur paralelizovat nelze Překážkou je nevyváženost počtu iterací Paralelizace zhoršuje lokalitu přístupů do paměti Skrytí latence za cenu sníženého cache hit ratio NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

108 Loop reversal Původní průchod Většina sousedů v průchodu je závislá J
K J

109 Loop reversal Upravený průchod Většina sousedů v průchodu je nezávislá
K J

110 A[J,K]:=A[J-1,K]+A[J,K-1]
Loop skewing Obecnější příklad for J:=1 to N do for K:=N-J to P do A[J,K]:=A[J-1,K]+A[J,K-1] K J

111 A[J,K]:=A[J-1,K]+A[J,K-1]
Loop skewing Obecnější příklad for J:=1 to N do for K:=N-J to P do A[J,K]:=A[J-1,K]+A[J,K-1] K J

112 “Paralelní” bsearch for ( i = 0; i < N; ++ i )
bsearch( a, M, b[ i]); void bsearch( a, M, x) { while ( /*...*/ ) if ( a[ j] > x ) j = /*...*/; else } bsearch_many( a, M, b, N); void bsearch_many( a, M, b, N) { while ( /*???*/ ) for ( i = 0; i < N; ++ i ) if ( a[ j[ i]] > b[ i] ) j[ i] = /*...*/; else } NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

113 Algoritmy a cache - další pohled
Přístup na náhodné adresy Schopnost přístupu na náhodné adresy je pro algoritmus klíčová bsearch, hash,... Nalezení příslušné buňky paměti je součástí užitečného výkonu algoritmu Program vykonává užitečnou práci pomocí adresních dekodérů paměti Adresní dekodéry jsou v paměti pořád - zaměstnejme je! Paměť má nezávisle pracující bloky - zaměstnejme je paralelně Přístup na předvídatelné adresy Předvídatelný (lineární) přístup nevyužívá schopnosti RAM Adresní dekodéry opakovaně dekódují podobné adresy Zbytečný hardware, zbytečná spotřeba energie Architektura RAM stroje je pro takové algoritmy nadbytečná Běžné programovací jazyky jsou této architektuře podřízeny Vystačili bychom s Turingovskou páskou Neumíme ji fyzicky realizovat Neumíme v tomto prostředí programovat NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek


Stáhnout ppt "Vývoj vysoce výkonného software"

Podobné prezentace


Reklamy Google