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

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

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

Podobné prezentace


Prezentace na téma: "1NPRG054 Vývoj vysoce výkonného software - 2013/2014 David Bednárek Vývoj vysoce výkonného software."— Transkript prezentace:

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

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

3 3NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

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

5 5NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

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

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

9 9 Motivační příklad

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

11 class Fruit {... virtual int seeds() = 0; }; class Apple : public class Fruit { virtual int seeds() { return...; }... }; class Orange : public class Fruit { virtual int seeds() { return...; }... }; vector 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 data; Motivační příklad 11NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

12 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 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 Motivační příklad 12NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

13 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 Motivační příklad 13NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

14  Výsledky testu  objektů  Celkem 10,4 ms  10,4 ns na objekt  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% Výsledky 14NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

15  64-bitový kód (Intel-64)  objektů  Celkem 10,4 ms  10,4 ns na objekt  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  objektů  Celkem 10,0 µs  10,0 ns na objekt Výsledky - porovnání architektur na témže HW 15NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

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

17 Příčiny 17NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

18 Příčiny 18NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

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

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

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

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

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

24 Intel Core Microarchitecture 24NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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)

25 Intel Core Microarchitecture 25NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

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

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

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

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

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

31 31NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

32 32 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 33 Scheduling  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 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 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 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 37 Příklad – Intel compiler – x64 /*...*/ k = i >> 1; j = 0; do { r8 = *p; r9 = *(p+1); s ^= r8; s ^= r9; p += 2; j += 1; } while ( j < k ); /*... */ 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

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

39  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  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 Kritický kód - Intel C++ 64-bit 39NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

40  Závislosti  write-read  read-write  test-access  Restart pipeline  Špatně predikovaný skok do virtuální funkce  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 Kritický kód - Intel C++ 64-bit 40NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

41  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] ret  Mikrooperace (odhad) loadeax,[8+rcx] loadt1,[rsp++] jmpt1 addr14,8 loadt2,[88+rbp] addt2,eax store[88+rbp],t2 cmpr14,r13,eflags jne.lp,eflags loadrcx,[r14] loadrax,[rcx] loadt3,[8+rax] store[--rsp],rip jmpt3 loadeax’,[4+rcx] loadt4,[rsp++] jmpt4 Kritický kód - Intel C++ 64-bit 41NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

42 1: loadeax,[8+rcx] 2: loadt1,[rsp++] 3: jmpt1 4: addr14,8 5: loadt2,[88+rbp] 6: addt2,eax 7: store[88+rbp],t2 8: cmpr14,r13,eflags 9: jne.lp,eflags 10: loadrcx,[r14] 11: loadrax,[rcx] 12: loadt3,[8+rax] 13: store[--rsp],rip 14: jmpt3 1': loadeax’,[4+rcx] 2': loadt4,[rsp++] 3': jmpt4 fetch+decodeloadALUretire+store '..3' ' ' Odhad provedení kritického kódu s neúspěšnou predikcí 42NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

43 1: loadeax,[8+rcx] 2: loadt1,[rsp++] 3: jmpt1 4: addr14,8 5: loadt2,[88+rbp] 6: addt2,eax 7: store[88+rbp],t2 8: cmpr14,r13,eflags 9: jne.lp,eflags 10: loadrcx,[r14] 11: loadrax,[rcx] 12: loadt3,[8+rax] 13: store[--rsp],rip 14: jmpt3 fetch+decodeloadALUretire+store ’4’4’ ’8’ ’ ’ ’1’..4’ 711’5’..8’ 0. 1’’4’’9’-10’ 1.. 2’’8’’ ’11’ 3.. 5’’ ’’ Odhad provedení kritického kódu s úspěšnou predikcí 43NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

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

45 Hodnocení výsledků 45NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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)

46 class Apple { int seeds() { return d2; } int d1, d2, d3; }; class Orange { int seeds() { return d3; } int d1, d2, d3, d4, d5; }; vector dataA; vector 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 Jiný přístup 46NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

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

48 vector Ad1, Ad2, Ad3; vector Od1, Od2, Od3, Od4, Od5; int s = 0; for_each( Ad2.begin(), Ad2.end(), [&]( int x) { s += x; }); for_each( Od3.begin(), Od3.end(), [&]( int x) { s += x; });  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 Sloupcově orientovaný přístup 48NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

49 vector Ad1, Ad2, Ad3; vector Od1, Od2, Od3, Od4, Od5; int s = 0; for_each( Ad2.begin(), Ad2.end(), [&]( int x) { s += x; }); for_each( Od3.begin(), Od3.end(), [&]( int x) { s += x; });  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 Sloupcově orientovaný přístup 49NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

50 #include vector 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 Sloupcově orientovaný přístup – SSE3 50NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

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

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

53 Shrnutí 53NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

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

55 Techniky ladění výkonu 55NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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í

56 Techniky měření chování programu 56NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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í

57 Techniky měření chování programu 57NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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.)

58 Techniky měření chování programu 58NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

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

60 Současné technologie polovodičových pamětí 60NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek Statická RAMDynamická RAMFlash EPROM Princip záznamuElektrický obvod se dvěma stabilními stavy Nabitý kondenzátor Výdrž záznamuPo dobu napájeníDesítky milisekundDesítky let Princip čteníMěření napětí na výstupu obvodu Vybití kondenzátoruOvlivnění vodivosti elektrickým polem kondenzátoru Princip zápisuZměna napětí vstupů obvodu Nabití kondenzátoruNabití/vybití kondenzátoru tunelováním Tranzistorů na bit611/3 Moorův zákon – dvojnásobná kapacita 2 roky1,5 roku1,4 roku Latence0.5-5 ns dle velikosti20-30 nsdle architektury Moorův zákon – poloviční latence ?7 let?

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

62 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 Architektura paměti DRAM 62NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek řádkový dekodér sloupcový dekodér adresa sloupce adresa řádku data řádkový buffer matice kondenzátorů

63 Typické rozměry řá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 Architektura paměti DRAM 63NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek řádkový dekodér 1:16384 sloupcový dekodér 32:8192 adresa sloupce 8 bit adresa řádku 14 bit data 32 bit řádkový buffer 8192 bit matice kondenzátorů

64 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 Architektura paměti DRAM – příklad čipu 64NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek data 32 bit dekodér banky 1:8 adresa banky 3 bit multiplexor 8*4:32 data 4 bit adresa 14 bit řídící signály banka 0banka 1banka 2banka 3banka 4banka 5banka 6banka 7

65 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 Architektura paměti DRAM - příklad 65NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek čip 3čip 2čip 1čip 0 čip 7čip 6čip 5čip 4 čip 11čip 10čip 9čip 8 čip 15čip 14čip 13čip 12 adresy a řízení data 64 bit

66 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ů Architektura paměti DRAM – typický 4GB DDR3 modul 66NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek rank 0 rank 1 adresy a řízení data 64 bit výběr ranku

67 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ší Architektura paměti DRAM - kanály 67NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek adresy a řízení data 64 bit výběr ranku rank 0 rank 1 modul 0 rank 2 rank 3 modul 1

68 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 Architektura paměti DRAM – dual channel 68NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek kanál 0kanál 1 rank 0 rank 1 modul 0 rank 2 rank 3 modul 1 rank 0 rank 1 modul 2 rank 2 rank 3 modul 3

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

70 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) Architektura paměti DRAM 70NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

71 Rozhraní procesor - DRAM 71NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

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

73 Řá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ů Architektura paměti SRAM 73NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek řádkový dekodér sloupcový dekodér adresa sloupce adresa řádku data matice klopných obvodů

74 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 Architektura paměti SRAM 74NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek adresa řádku a sloupce adresa banky data

75 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 Architektura paměti SRAM 75NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek

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

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 Asociativní paměť 77NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek tagdata tagdata ========

78 SRAM 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é Asociativní paměť 78NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek tag data = index

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 Asociativní paměť 79NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek tag data index SRAM = = =

80 Cache poslední úrovně 80NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  LLC = L2 nebo L3  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í

81 Cache prostřední úrovně 81NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

82 Cache první úrovně 82NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  L1D  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)

83 TLB 83NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

84 Typické použití bitů adresy (Intel Sandy Bridge) 84NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek bit virtuální adresa DTLB1 tag index assoc TLB2 tag index assoc fyzická adresa L1D tag index assoc L2 tag index assoc L3 tag index assoc velikost256 TB1 TB16 MB1 MB64 KB4 KB64 B

85 Typická latence a propustnost – Intel Sandy Bridge 85NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek latence (cykly) operací/ cyklus B/operaceB/cyklusGB/s [3 GHz CPU] registry0 (započteno v čase instrukce) teoreticky 14, prakticky až 112 SIMD až 160 teoreticky 480 L1D43 (2*R+1*W) L L DDR dual channel cca 1202/ regL1L2L3DRAM

86 Typická latence a propustnost – Intel Sandy Bridge 86NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek regL1L2L3DRAM Quad Core

87 Důsledky pro programování 87NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

88 88NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek 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)

89 Úrovně cache 89NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

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

91 91NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

92 Cache-oblivious algorithms (zjednodušený pohled) 92NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  Cache-oblivious algorithms [1999]  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 n 2 >C každý přístup (k pravému operandu) generuje cache miss  O(n 3 ) - nezávisí na C; g(C) = 1  Cache-oblivious algoritmus (rekurzivní dělení)  O(C -1/2 *n 3 ) tj. g(C) = C -1/2

93 Cache-oblivious algorithms 93NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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í

94 Cache-oblivious algorithms 94NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  Rozděl a panuj  Problém P 0 se dělí na podproblémy P 1 a P 2  Pamětová složitost: m 0 < m 1 + m 2  Část dat D 12 je používána oběma podproblémy: |D 12 | = d 12 = m 1 + m 2 - m 0  Pro m 0 > C se problém P 0 do cache nevejde  Část dat D 12 pravděpodobně bude čtena pro P 2 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 P 0 přispěje druhým čtením D 12 o velikosti d 12

95 Násobení matic - rozděl a panuj 95NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  C = A * B, velikosti A[i,k], B[k,j], C[i,j]  i-split - dělení problému v dimenzi i  i 0 = i 1 + i 2 ; j 0 = j 1 = j 2 ; k 0 = k 1 = k 2  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: d 12 = k 0 * j 0  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 d 12 a jiné rozměry podúloh  Končíme u velikosti m 0 = i 0 *k 0 + j 0 *k 0 + i 0 *j 0 < C  Pod touto velikostí je z hlediska opakovaných výpadků cache cena 0

96 Cache-oblivious algorithms 96NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  Normalizace  Časová složitost: t 0 = t 1 + t 2  Počítáme g(C)  počet (druhých a dalších) přístupů do hlavní paměti na jednotku času  g 0 (C) = d 12 /t 0 + g 1 (C) * t 1 /t 0 + g 2 (C) * t 2 /t 0 pro m 0 > C  g 0 (C) = 0 pro m 0 < C  Násobení matic - i-split  i 0 = i 1 + i 2 ; j 0 = j 1 = j 2 ; k 0 = k 1 = k 2  d 12 = k 0 * j 0  Časová složitost t 0 = i 0 *j 0 *k 0 ; t 1 = i 1 *j 0 *k 0 ; t 2 = i 2 *j 0 *k 0  Normalizovaný počet opakovaných přístupů k hlavní paměti  g 0 (C) = 1/i 0 + g 1 (C) * i 1 /i 0 + g 2 (C) * i 2 /i 0  Při dělení napůl i 1 = i 2 ; g 1 (C) = g 2 (C)  g 0 (C) = 1/i 0 + g 1 (C)

97 Násobení matic - rozděl a panuj 97NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  Rekurzivní kroky  i-split: g i,j,k (C) = 1/i + g i/2,j,k (C)  j-split: g i,j,k (C) = 1/j + g i,j/2,k (C)  k-split: g i,j,k (C) = 1/k + g i,j,k/2 (C)  Končíme u velikosti i F *k F + j F *k F + i F *j F < C  Rozhoduje součin dvou největších rozměrů  Pro dané počáteční a zvolené koncové  Cena rekurzivního sestupu nezávisí na cestě:  g S (C) = 1/i S /i F + 1/j S /2j F + 1/k S /2k F  1/2i F + 1/2j F + 1/2k F < g S (C) < 1/i F + 1/j F + 1/k F  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 i S > j S > k S  i F = j F = k F = C 1/2 pro k S > C 1/2 ; cena g S (C) = O(C -1/2 )  i F = j F = C 1/2 ; k F = k S pro j S > C 1/2 > k S ; cena g S (C) = O(C -1/2 )  i F = C / j s ; j F = j S ; k F = k S pro i S > C 1/2 > j S ; cena g S (C) = O(j s /C)  i F = i s ; j F = j S ; k F = k S pro C > i S * j S ; cena g S (C) = 0

98 Násobení matic - cache-aware 98NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  Nejlepší koncový bod pro i S > j S > k S  i F = j F = k F = C 1/2 pro k S > C 1/2 ; cena g S (C) = O(C -1/2 )  i F = j F = C 1/2 ; k F = k S pro j S > C 1/2 > k S ; cena g S (C) = O(C -1/2 )  i F = C / j s ; j F = j S ; k F = k S pro i S > C 1/2 > j S ; cena g S (C) = O(j s /C)  i F = i s ; j F = j S ; k F = k S pro C > i S * j S ; cena g S (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í C 1/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 g S (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í

99 Násobení matic - cache-oblivious 99NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  Nejlepší koncový bod pro i S > j S > k S  i F = j F = k F = C 1/2 pro k S > C 1/2 ; cena g S (C) = O(C -1/2 )  i F = j F = C 1/2 ; k F = k S pro j S > C 1/2 > k S ; cena g S (C) = O(C -1/2 )  i F = C / j s ; j F = j S ; k F = k S pro i S > C 1/2 > j S ; cena g S (C) = O(j s /C)  i F = i s ; j F = j S ; k F = k S pro C > i S * j S ; cena g S (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)

100 Cache-oblivious algorithms – vliv bloků 100NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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ě

101 Cache-oblivious algorithms – vliv bloků 101NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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(n 3 ) - 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 B 1/2 * B 1/2 se složitost zlepší na O(B -1/2 * n 3 )  Cache-oblivious algoritmus (rekurzivní dělení, rekurzivní uložení)  O(C -1/2 *B -1 *n 3 ) 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)

102 Ideální algoritmus 102NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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)

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

104 Algoritmy a cache 104NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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; /*...*/ }

105 Algoritmy a cache 105NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

106 Algoritmy a cache 106NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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; /*...*/ }

107 Algoritmy a cache 107NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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

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

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

110 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]  110 K J

111 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]  111 K J

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

113 Algoritmy a cache - další pohled 113NPRG054 Vývoj vysoce výkonného software /2014 David Bednárek  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


Stáhnout ppt "1NPRG054 Vývoj vysoce výkonného software - 2013/2014 David Bednárek Vývoj vysoce výkonného software."

Podobné prezentace


Reklamy Google