párhuzamos programozás… -...

Post on 17-Oct-2019

6 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

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