GPU-Computing mit CUDA und OpenCL in der Praxis
-
Upload
joern-dinkla -
Category
Technology
-
view
1.590 -
download
4
description
Transcript of GPU-Computing mit CUDA und OpenCL in der Praxis
GPU-Computing mit CUDA und OpenCL
in der Praxis
24. Mai 2012
Jörn Dinkla
Motivation
Vom Modell zum Bild
Computer-Grafik
Tomas Akenine-Mőller © 2002, Quelle: http://www.realtimerendering.com/
Quelle: Tomas Akenine-Mőller © 2002
Echtzeit-Grafik
Vertex Pixel
Rückblick
1992 … 1995 …
T&L in Hardware
1999 2000
Fixed pipelines
DirectX 7.0
Programmierbare Shader
2001 2002
DirectX 8.0 DirectX 9.0
Shader-Sprachen
2003 2004 2005
HLSL, Cg, GLSL
GPGPU
Unified Shader
2006 2007
DirectX 10.0
GPU-Computing
2006 2007 2008 2009
CUDA
CTM Stream SDK
OpenCL
DirectX 11.0
Massiv Parallel
Schneller, Größer, Besser
Höhere Geschwindigkeit
Parallelisieren?
1080p 4K2D / QFHD 720p 576p 480p
1. Golden Code
Sequentiell und korrekt
2. Golden Code parallelisieren
3. Zu GPU-Code transformieren
Entwicklungs-Methodik
Parallelität finden
Eingabe
Verarbeitung
Ausgabe
Eingabe
Ausgabe
#1 #2 #3
Parallelität finden
Eingabe
Verarbeitung
Ausgabe
E1
A1
#1
E2
A2
#2
E3
A3
#3
Parameter: Eindeutige ID
Hole Daten anhand ID
Verarbeitung
Speichere Daten anhand ID
SPMD / SIMT
E1
A1
#1
E2
A2
#2
E3
A3
#3
uchar4 p;
p.x = x+y;
p.y = x-y;
p.z = y;
p.w = 255;
SIMT: Lock-step
1 2 3 4
1 2 3 4
Frameworks
Hardware
Low Level
Praktisch
Besser
CUDA Driver API Open CL
CUDA Runtime
API
Komfortabel
Thrust? PyCUDA /
PyOpenCL ?
C++ cl.hpp
OpenACC ? C++ AMP?
Plattform-Unabhängigkeit ?
HelloWorld.cu
CUDA Runtime API
Kernel
Host
Programm zu Code
Host Code
C/C++
Device Code
(Kernel)
Compiler
Machine Code
Compiler
LLVM / PTX / IL
Assembler
Assembler /
LLVM
Cubin / Machine
Code
Assembler (*)
JIT?
JIT?
Vorteile
„Plattformunabhängig“
CPU+GPU
Vektorberechnungen
Aber
Performance von Device abhängig
„Komiteesprache“
OpenCL
OpenCL / Driver API
Device
Context
Program
Kernel
Command Queue
Plattform
Aufruf
WebCL
Siehe http://webcl.nokiaresearch.com/kerneltoy/
Smoothing
3x3 Fenster
Smoothing
0 1 2 3 4
0
1
2
3
4
0 1 2 3 4
0
1
2
3
4
0 1 2 3 4
0
1
2
3
4
Für alle x,y,z in vol
sum = 0, c = 0
Für alle dx,dy,dz in Nachbarschaft
sum += vol[x+dx,y+dy,z+dz]
c += 1
vol‘[x,y,z] = sum / c
Algorithmus
Threads
Extension / Größe
width, height, depth
index(x,y,z)
inBounds(x,y,z)
Extent
0 1 2 3
0
1
2
3
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Accum
Akkumulator
add(value)
Akkumuliert int4
avg()
Durchschnitt
0 1 2 3 4
0
1
2
3
4
Golden Code
Fermi (GTX 580)
x*y*z Threads Cores/SMs
Thread-Block / Work group / Tile
Grid / NDRange
Kernel-Konfiguration
0 1 2 3 4 5 6 7
0
1
2
3
4
5
6
7
0 1 2 3 4 5 6 7
0
1
2
3
4
5
6
7
0 1 2 3 4 5 6 7
0 T T T T T T T T
1 T T T T T T T T
2 T T T T T T T T
3 T T T T T T T T
4 T T T T T T T T
5 T T T T T T T T
6 T T T T T T T T
7 T T T T T T T T
ExecConfig
grid
threads
stream
ExecConfig(Extent)
Kernel-Konfiguration
Überblick H
ost
Algorithmus Buffer Buffer‘
Ho
st
Buffer Buffer‘
De
vic
e
Kernel Buffer Buffer‘
Ho
st
Buffer Buffer‘
De
vic
e
Kernel Buffer Buffer‘
Device-Speicher
cudaMalloc(), cudaFree()
Host-Speicher
cudaMallocHost(), cudaFreeHost()
Transfer
cudaMemcpy()
Speicher-Management
Host-Speicher
Virtueller
Speicher
Physikalischer
Speicher
malloc() cudaMallocHost()
Device
Speicher
BaseBuffer
malloc(), free()
HostBuffer
PinnedHostBuffer
DeviceBuffer
copyFrom(), copyTo()
Versionierung
Buffer
BufferPair
Paar
Host-Buffer
Device-Buffer
Methoden
updateDevice()
updateHost() H
ost
Buffer Buffer‘
De
vic
e
Kernel Buffer Buffer‘
GPU-Code
Performance-Vergleich
Größe CPU GPU Speedup GPU+C Speedup
8 0 0 2 0,00
16 1 0 2 0,00
32 2 0 4 0,00
64 15 0 4 0,00
128 97 4 24,25 10 9,70
256 660 23 28,70 63 10,48
384 2216 78 28,41 204 10,86
512 5249 184 28,53 482 10,89
Nur GPU Mit Kopien
Und größer ?
Speicherplatz: N^3
Größere Volumen
Swapping
Host
Device
BufferIterator
Kernel: Anpassen
BufferPair: Erweitern
Swapping
Auslastung D
evic
e
Ho
st
I
K I O
O I
K I O
O I
K I O
O
La
st
Streams & Overlap
Schritt Ein Stream Stream 1 Stream 2 Stream 1 Stream 2
1 H2D H2D H2D
2 Kernel 1 Kernel 1 H2D Kernel 1 H2D
3 D2H D2H Kernel 2 D2H Kernel 2
4 H2D D2H H2D D2H
5 Kernel 2 H2D Kernel 3
6 D2H Kernel 3 D2H
7 H2D D2H
8 Kernel 3
9 D2H
Kernel + Kopie
überlappend
Kernel + Kopie und
H2D und D2H
Initialisierung
Parallel Für alle „ungeraden“ Partitionen p
Kopiere H2D für p in s1
Rufe Kernel auf für p in s1
Kopiere D2H für p in s1
Für alle „geraden“ Partitionen q Kopiere H2D für q in s2
Rufe Kernel auf für q in s2
Kopiere D2H für q in s2
Swapping & Streaming
Asynchron
Asynchrone Kopien
Übersicht H
ost
Buffer Buffer‘
De
vic
e Kernel Buf‘ 1
Kernel Buf 2 Buf‘ 2
Buf 1
Buf 2
Double Buffering H
ost
Buf 1 Out 2
De
vic
e Kernel Out 1
Kernel Buf 2 Out 2
Buf 1
Volumen
Input
Volumen
Output
Out 1
HostBufferPair
Analog zu BufferPair
Buffer
HostBuffer
PinnedHostBuffer
Unterschiedliche Größe
updateFrom(), updateTo()
Klasse
Größe CPU GPU Speedup
8 0 0
16 0 0
32 10 0
64 20 0
128 110 0
256 660 23 10,48
384 2233 80 10,86
512 5263 183 10,89
768 17707 1718 10,31
1024 42101 4079 10,32
1152 59156 5924 9,99
Performance-Vergleich
GTX 580
1632,3 GFLOPS und 194,5 GB/s
Wen es interessiert:
GFLOPS #Cores * Shader-Takt * 2
GB/s Breite [Byte] * Memory-Takt * x
GDDR3: x = 2, GDDR5: x = 4
Theorie
Pro Kernel
27 Laden, 1 Speichern
638 Operationen
Arithmetische Intensität
Bei 512er Test
467,93 GFLOPS
20,54 GB/s
Optimierungspotential vorhanden!
Pi mal Daumen
Maximiere …
1. Parallelität
2. Speicherdurchsatz
3. Berechnungsdurchsatz
Optimierung
Streams
Asynchrone Kopien und Kernel
Auslastung des Device
Grid
Auslastung der SMs
Thread-Block
„Occupancy“
Maximiere Parallelität
Mehrere Thread-Blöcke pro SM
Speicherzugriffe verstecken
O(1) Scheduler
Occupancy
TB SM TB TB TB TB -- -- --
Occupancy Calculator
Speicher-Architektur
CPU 1
Core
L1 / L2
Core
L1 / L2
L3 Cache
Global Memory
Bus / Memory Controller
GPU
Global Memory
Constant Texture
Prozessor (SM)
Local / Shared / L1
Registers
C C C C
L2 Cache
8-16 8-20
160-
200
1600
8000
„Coalesced“ Zugriffe
32, 64, oder 128-byte
„Alignment“
Max. Speicherdurchsatz
Pinned-Host-Speicher
Minimiere Kopien
Benutze On-Chip-Speicher
Shared/Local, Register
Konfiguriere Cache
Max. Speicherdurchsatz
int tid = treadIdx.x;
if (tid < 2) {
o[tid] = 1;
} else {
o[tid] = 2;
}
Divergenz
1 2 3 4
1 2 3 4
Minimiere Divergenz
Loop-Unrolling
Berechnen statt Speichern
Arithmetik
Präzision vs. Geschwindigkeit
Fusion von Kerneln
Max. Berechnungen
Synchronisation
Innerhalb Thread-Block
__syncthreads()
Atomare Zugriffe
atomicAdd()
Speicher
Zwischen Kernel-Aufrufen
Weiterführend …
JNI
JCuda
Javacl, Jocl
Eigenes API
Aparapi, Java-GPU
JVM
JVM
Hardware
Low Level
Praktisch
Besser
CUDA Driver API Open CL
CUDA Runtime
API
Komfortabel
C++ cl.hpp
JCUDA
JavaCL
CUDA mit Java
Hello, Groovy CUDA!
JCUDA
Hello, Groovy OpenCL!
JavaCL
Hello, Scala + GPU
JavaCL
Vorteile
Entwicklungsgeschwindigkeit
Host-Code
Nachteile
Datentypen
Getrennt Debuggen
Fazit JVM
„Richtig“ eingesetzt unschlagbar!
Folien & Code
http://dinkla.net/parallel2012
Fazit
Sanders, Kandrot
CUDA by Example
Kirk, Hwu
Programming Massively
Parallel Processors
Literatur: CUDA
Scarpino
OpenCL in Action
Gaster et.al.
Heterogeneous Computing
With OpenCL
Literatur: OpenCL
Hwu (Ed.)
GPU Computing Gems
Emerald Edition
Hwu (Ed.)
GPU Computing Gems
Jade Edition
Literatur: CUDA