párhuzamos programozás… -...
Post on 17-Oct-2019
6 Views
Preview:
TRANSCRIPT
Párhuzamos
programozás…
… a gyakorlatban
Tódor Balázs
cougar@sch.bme.hu
Tematika
Erről lesz szó
1 PC
C++
OpenMP, thread-ek
Közös memória
Használati technikák, trükkök
Erről nem
Sok PC (grid, cluster)
C#, Java, Python
MPI, process-ek
Elosztott memóriás modell
Mi a mutex, CS, stb.
Tartalom
Párhuzamosítás 1x1
Eszközök, technikák
FP, AP, kommunikáció
Tervezés
Az eddigiek használata
Top-down/Bottom-up
Egy lehetséges jövő
Stream programming
Miért?
Hány processzorod van?
A GPU számít?
1 CPU
2, 4, 8,… mag
Moore törvénye: 1,5 évente x2 mag
Kihasználtság
50%, 25%, 13%, …
Core i7 = 8 mag
Párhuzamosítás 1x1
Független feladatok azonosítása
Megjelenítés + számolás
Zene + kezelőfelület
Beolvasás + helyesírás
Külön szál minden feladatnak
Eszközök: Intel TBB, boost
Kölcsönös kizárás
printf
Kommunikáció
teljes függetlenség nem szokott lenni
Zab és bab
Független feladatok
Zab
Bab
Két külön szál
Eszközök
Boost::thread
OpenMP
Válogatás
BabmosásZabmosás
HámozásHegyezés
Csomagolás Csomagolás
Vége
Boost
„STL++”
Platformfüggetlen, ingyenes
Mit tud?
Array, circular buffer, bitset
Graph, FSM
File system, függvénypointerek
Thread, mutex, stb.
Any, variant, konvertálás
String algoritmusok
Boost::thread
Thread
Ctor
Join
ThreadFunc
Függvény
N paraméter
Válogatás
BabmosásZabmosás
HámozásHegyezés
Csomagolás Csomagolás
Vége
boost::thread
zabThread(ZabFunc);
zabThread.join();
babThread.join();
boost::thread
babThread(BabFunc);
OpenMP
Fordítóba beépített
Intel, MSVC, gcc
Minimális kódmódosítás
„#pragma omp”
Multiplatform
Linux, Win32, stb.
Rugalmas
AP, FP, mutex, CS, single/master, stb.
OpenMP
Parallel
OMP
engedélyezése
Sections
Párhuzamos blokk
Section
Szálak
létrehozása
Barrier
Join_all
Válogatás
BabmosásZabmosás
HámozásHegyezés
Csomagolás Csomagolás
Vége
omp parallel
omp sections
omp barrier
omp section omp section
OpenMP vs boost
OpenMP
boost
Funkcionális párhuzamosítás
Független funkciók
Kölcsönös kizárás
Kommunikáció
... egyszerű, gyors, rugalmatlan
2x annyi szál?
Fizikai szimuláció
Ütköztetés 1.
NxN
R: objektumok
Feloldás
N
R: objektum
W: objektum
dSpaceCollide NearCallback Step
Ütköztetés 2.
NxN
R: objektumpár
W: contact-ok
Fizikai szimuláció
Feladatok dSpaceCollide: (1*N)*N
NearCallback: (1*N)*N
Step (1*N)
Független feladatok (collide+near+step)
(collide+near+step)
(collide+near+step)
...
Azonos funkció, sok szál
Rugalmas, egyszerű
De: csak független adatokon
Parallel for
Ciklusváltozósigned int
Összehasonlításegyszerű
Léptetéskonstanssal
KiugrásBreak, continue,
goto
fork
join
Közös erőforrások
Az írás-olvasás
között más is
beleírhat.
Kölcsönös kizárás
vagy
Csak olvasás
Közös változó
Írás
Olvasá
s
Explicit saját változó
Saját változó
Implicit saját változó
Saját változó
Közös és saját
Egy tömb összes elemét akarjuk
összeadni
Mi legyen a célváltozó?
Közös, mert meg akarjuk tartani
Saját, mert többen is írnának bele
Ha közös?
Kölcsönös kizárás (lassú)
Ha saját?
Eltűnik amit beleírunk!
Redukció
Közös változó
Redukció bekapcs.
Implicit: sajátok -> közös
Explicit: saját változó
Fizika és AP
Collide
N szál
NearCallback
Ír a contact-ok listájába -> lock
Step
N szál
… máshol keressük a függetlenséget!
Fizikai szimuláció:
függetlenség A különböző „szigetek” függetlenek
Számolhatjuk őket külön szálakon
Collide: N*N
PhysX, ODE
Legjobb eset
egyforma szigetek
Legrosszabb eset
N, 1, 1, 1
Ez gyakorlatilag egyszálú
Fizikai szimuláció:
függetlenség A különböző „szigetek” függetlenek
Számolhatjuk őket külön szálakon
Collide: N*N
PhysX, ODE
Legjobb eset
egyforma szigetek
Legrosszabb eset
N, 1, 1, 1
Ez gyakorlatilag egyszálú
„Legrosszabb eset”
Funkcionális
lassú/gyors eljárások külön szálon
pl. beolvasás + helyesírásellenőrzés
Adat
kevés/sok adat: N, 1, 1, 1
Nem egyforma műveletek
Statikus kiosztás
Hány szál van?
Melyik szál mit csinál?
A megoldás
Skálázhatóság
Feladat és végrehajtás külön
Dinamikus erőforráskiosztás
Szálak közötti feladatmozgatás
N, 1, 1, 1 -> N/2, 1+N/2, 1, 1
Lassú, gyors -> gyors+lassú/2, lassú/2
Hibrid rendszerek
Taszk
Funkciórész + valamennyi adat
Kicsi: jobb kihasználtság
Nagy: kevesebb szinkronizáció
Ütemező
Taszk-szál összerendelés
Egyszálas (gyors legyen)
Erőforrás
Processzor (szálak)
HDD, user (képernyő, billentyűzet)
Fizikai szimuláció: gráfban
Ütemezés
Mikor futhat egy taszk?
Bemenet (producer-consumer)
Erőforrásigények
Olvasás/írás?
Gyors, egyszerű
Critical section-ben fut
Amdahl törvénye
Amdahl
A „varázsképlet”:
P: párh./soros arány
N: CPU-szám
Jól gondold meg hol lockolsz!
Ütemezés
Taszk
list<Object*>
m_apWriteLocks;
list<const Object*>
m_apReadLocks;
bool CanRun(const
guard&);
CanRun()
Erőforrások
Bemenetek
LOCK
task=list.front()
task.CanRun()
list.move(task, vége) list.pop_front()
UNLOCK
Task.Run()
true false
Hibrid rendszerek
A végrehajtás és a feladat független
Skálázható
Legyen elég taszk
Logikus: irányított gráfból hozható létre
Párhuzamosítás 1x1
Független feladatok azonosítása
Szálak létrehozása
Kölcsönös kizárás
Olvasás, írás
Kommunikáció
Közös erőforrások
Kommunikáció
Producer-consumer
Kölcsönös kizárás
Olvasás vs írás
Olvasni: akárhányan
Írni: csak egy
Tanulság: olvasni jó
HL2 (Source): 95%
Eszközök
Mutex, Critical Section, stb.
Egyik sem biztonságos
De mindegyik lassú
Kommunikáció
Nincs kizárás
Atomi műveletek
Lockless
Hardware-es kölcsönös kizárás
Kölcsönös kizárás
Mutex, CS, stb.
Kettős pufferelés
Igazi garázsbaillő megoldás
Atomi megoldások
Hardverfüggő
1 db aligned read/write mindig atomi
iValue = 0;
++a
Beolvasás+növelés+visszaírás = 3
OpenMP: 'atomic' kulcsszó
Több atomi művelet?
Több atomi művelet
Tipikus hiba
iData = 5; bValidData = true;
Ellenségünk: instruction reordering
Az MMU blokkokban írja a memóriát
Főleg XBox, de PC-n is előfordul
Megoldás
Critical section
Platformfüggő: barrier utasítások
Lockless
„Lock”
Lock, tárolás, unlock
Lassú, ismert, biztonságos
„Lockless”
CompareAndSwap utasítás
Sok lock megoldás erre épül
Lockless
Láncolt lista
old=NULL
CAS(head, old, new)
false -> head=old, újra
Tulajdonságok
Gyors (hardveres)
Végrehajtási idő?
Prioritások?
ABA-probléma
A != A
ABA-probléma
A probléma
Thread1: A->B->A
Thread2: CAS(&p, A, C)=true
Mikor jön elő?
Az ‘A’ érték nem a teljes állapotot tárolja(A!=A)
Pl. A = pointer
A megoldás
32b: DCAS: 64 bit (32b pointer + azonosító)
64b: aligned pointerek + bitbuherálás
ABA-probléma: láncolt lista
A lista
struct { Obj* next; } *
Eredetileg: A, B
Műveletek
Thread1: read A (nincs pop)
Next = A.next (B)
Thread2: pop A, pop B, push A
A.next = NULL
Thread1: CAS(head, A, C)
true, de C.next = B !
Lockless: miért jó?
Nincs deadlock (és ez a helyes megoldás?!)
Nincs prioritásinverzió
Prioritásörökléssel is megoldható
Mondjuk itt prioritás sincs…
Nincs sorbanállás „… a kamion a leggyorsabb”
Interrupt handler
Malloc, interrupt, a handler-ben malloc?
Hatékonyabb, mint a mutex
Nagy méretű tömb esetén hogy lockolsz?
Szünet
Végig maradt Szünetben hazament
Párhuzamos problémák
Instruction reordering
A=5; B=1; -> B=1; A=5;
CS, barrier
Változók regiszterekben
„Tudatlan” fordítók
Volatile kulcsszó
False sharing
Nem hiba, csak lassú
False sharing
Struct: A, B elemek
Thread1: A-t használja
Thread2: B-t használja
Helyesen működik
Független feladatok
Nem kell kölcsönös kizárás
Rém lassú… miért?
False sharing
Thread1: A=1;
Cache line „piszkos”
Core2: cache line „érvénytelen”
Thread2: ++B
L1 Cache line „érvénytelen”
Újraolvasás: RAM->L2->L1->B
Megoldás:
Egy cache line = egy core
Kettős pufferelés
Memóriaigényes: két példány
Késik egy „swap”-et
Nincs lock
Kivéve: swap
Hatékony
Funkcionálisan párhuzamos rendszerek
Erősen összekötött rendszerek
Intel „Smoke”
Rendszerek: MI, fizika, grafika, hang, input
Az FP a legszebb, de…
Fizika -> MI, gfx, hang
gfx -> MI
Input->fizika
Change manager
Inkább késsen, mint lockoljon
„Kettős puffer továbbfejlesztve”
Intel „Smoke”
FP volt, hibrid lett
1 nagy feladat = sok (soros) taszk
Egyszerűbb, mint a teljes párhuzamosítás
A rendszerenkénti futási idő nem változik
De jobb kitöltés -> „párhuzamosíthatóbb”
Intel „Smoke”
Observer: Saját másolat a közös objektumokból Nincs lock, amikor olvasol
Cserébe késik az információ
Change Controller: per frame szinkronizáció 1 frame késés
Sok rendszer?
Intel „Smoke”
Fix időnként átviszi a változásokat
Clock: game clock (lehet renderfüggetlen)
Lock technikák
Hol lockolunk?
„adathoz v. kódhoz” közel
Lock helyett guard
Private változók = nincs lock!
Thread Local Storage
„Multithreaded Singleton”
A mutex:adat arány
1:1, N:1, 1:N
Hol lockoljunk?
Működik?
Igen
Bővíthető?
Nehezen
(Enter/Leave)
Skálázható?
Nehezen (FP)
lock
unlock
Hol lockoljunk?
Van egy osztály... több szál akarja használni.
nem thread safe
nem thread safe
Hol lockoljunk?
Külső lock
Majd megoldja valaki…
+3 nap debuggolás / osztály (~270eFt)
Belső lock
Az osztály magának elintézi
Esetek 90%-a
Hívó által biztosított
A hívónak bizonyítania kell, hogy lockolt
Ez a +10%
Belső lock
Biztonságos
Teljesen thread safe
„Idiótabiztos”
Kívülről láthatatlan
Bárki használhatja az osztályt
Rugalmatlan
Annyi lock, ahány művelet.
guard
guard
Hívó által
bizonyíték
Hívó által
Nem az igazi...
Mit bizonyít egy lock_guard<mutex>?
Kinek a mutexe?
Továbbfejlesztési lehetőségek
Típusos lock_guard
Lock_guard<Type>
Fordítási idejű ellenőrzés
Pointeres lock_guard
Lock_guard<Type>.m_pOwner
Futási idejű ellenőrzés
1:1
1 adat, 1 mutex
Lock: minél közelebb
Erre van a Get/Set
Tömbök?
1:N
„Modulo N” lockolás:
pl. páros/páratlan
Mitől függ az N?
Szálak száma
Egy szál hány elemhez fér hozzá egyszerre
Hívó általi lock
1 lock, N művelet
Ez is 1:N!
Gyorsabb… de „egyszálúbb”
explicit lock
implicit unlock
N:1
Több mutex egy adathoz?
„A” szál lefogja az egyiket...
„B” szál a másikat...
Sok-sok debuggolás…
Intel Thread Checker
1000 USD
Tartalom
Párhuzamosítás 1x1
Eszközök, technikák
FP, AP, kommunikáció
Tervezés
Az eddigiek használata
Top-down/Bottom-up
Egy lehetséges jövő
Stream programming
Hogyan párhuzamosítsunk?
Hol kell párhuzamosítani?
Leglassabb részek keresése
90/10-es szabály
Független feladatok azonosítása
Sugárkövetés
Videófeldolgozó program
Megközelítés
Top-down
rendszerszinttől, lefelé
Bottom-up
közvetlenül ott, ahol szükséges
„Call stack” módszer
Breakpoint a 10%-ba
Melyik szinten érdemes próbálkozni?
Példa
Független részek
Pixelek
Leglassabb
Sugár-test metszés
Top-down
Pixelek
Bottom-up
Testek
Sugarak
Független részek
Pixelek
Képkockák
Leglassabb
Motion blur
Top-down
Képkockák
Bottom-up
Pixelek
Előre tervezés
Milyen új funkciók lehetnek?
Mit kéne tudnia egy év múlva?
Milyen új adatok lehetnek?
Több?
Más?
Merre fejlődik a hardver?
Több mag
SIMD, SIMT
Előre tervezés
Általában több adat kerül be mint funkció
Videófeldolgozás
A frame-ek száma gyorsabban nő, mint a
pixeleké
Raytracer
Szebb képhez több sugár/test ütközés kell
Kompromisszum?
FP mellett OpenMP-s AP
Mindegy mit csinálsz, az OpenMP még belefér
Párhuzamos optimalizáció
Ami gyors egy szálon, az nem biztos, hogypárhuzamosítható is.
Mátrixszorzás:
Triviális: O(n3)
Strassen: O(n2,81)
Mátrixszorzás
Triviális
4 szál
Azonos terhelés
Strassen
7 szál, aztán 4
Eltérő terhelés
Soros rész!
Tartalom
Párhuzamosítás 1x1
Eszközök, technikák
FP, AP, kommunikáció
Tervezés
Az eddigiek használata
Top-down/Bottom-up
Egy lehetséges jövő
Stream programming
A jövő
Intel core i7
8 mag
GPU
8800 GTS = 112 mag (GTX 280: 240)
Nem csak grafikára
Hogyan programozzuk? HLSL, BrookGPU
CUDA / AMD Stream
OpenCL
C++ (Larrabee)
Stream programming
HLSL, Brook Pixel shader, adat=textúra, kimenet=rendertarget
1 helyre írás
CUDA/Stream „Scatter write”
Gyártófüggő
OpenCL AMD, Apple, nVidia, stb.
2009
Larrabee > 25 db P54C
C++
… „Linux a videókártyán”
Stream programming
(olvas, feldolgoz, ír)xN
Sok, független adat (N>1000)
Teljesen azonos feldolgozás (SIMT)
Divergencia?
Mi hiányzik?
Rekurzió
Pointerek
Össze-vissza írás/olvasás
Feltételek/ugrások
CUDA
Szálkezelés
Buta, gyors (~1000)
SIMT
Adatkezelés
Tömb (textúra)
Konstans tömb
Háromszintű memória
Kommunikáció
Barrier (__syncthreads)
CPU-s emuláció
printf
CUDA
ThreadID adat index
Közös memória Local: blokkon belül
Global: grid-en belül
Barrier Blokkon belül
Kernel float *pIn, *pOut (stream!)
Adat: pIn[threadID]
CUDA példa
Thread ID
Kernelhívás
Összefoglalás
Funkcionális vagy adatpárhuzamosítás FP: ha független funkciók vannak
AP: ha sok független adat van
N~1000 -> stream
Hibrid rendszerek Adatfolyamgráfból -> Taszk + ütemező
OpenMP-vel FP/AP együtt
Kommunikáció, lock Atomi/Lockless/lock
adathoz közel
Elérhetőség
Letöltés
www.mit.bme.hu/~szell/parhuzamos
Kérdések
Tódor Balázs, cougar@sch.bme.hu
Köszönöm a figyelmet!
A. Alexandrescu: „Multithreading and the C++ Type System”
T. Refenes: „How to Start a Multi-Threading RelationShip”
C. Breshears: „8 Simple Rules for Designing Threaded Applications”
T. Mattson, L. Meadows: “A „Hands-on‟ Introduction to OpenMP”
Intel: „Designing the Framework of a Parallel Game Engine”
T. Leonard (Valve): „Dragged Kicking and Screaming: Source Multicore”
Bruce Dawson (XNA): „Multicore Memory Coherence: The Hidden Perils of Sharing Data”
Cyril Zeller(nVidia): „CUDA Tutorial”
Jon Olick (id): „Current Generation Parallelism In Games”
Ian Buck (nVidia): „Programming CUDA”
Intel: „Smoke demo”
ODE: Open Dynamics Engine
Boost C++ libraries
Khronos Group: OpenMP, OpenCL
Geoff Langdale: „Lock-Free Programming”
Wikipedia: „Strassen algorithm”
top related