Hauptseminar MAP08
Random Heightmap on GPU
Hannes Stadler, Sebastian Graf
HannesStadler@gmx.de, sebgr@gmx.net
Betreuung: Matthias Hartl, Hritam Dutta, Frank Hannig
Hardware-Software-Co-Design
Universität Erlangen-Nürnberg
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
1
Gliederung
Was ist eine Heightmap?
Fault Algorithmus
Parallelisierung des Fault Algorithmus
Umsetzung in Cuda
Benchmarks
Probleme
Zusammenfassung
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
2
Was ist eine Heightmap?
dt. Höhenfeld
Zwei-dimensionales Skalarfeld
Beschreibung eines Höhenreliefs
Jedem Punkt ist ein Wert zugeordnet, der dessen Höhe
angibt
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
3
Fault Algorithmus
Erzeuge ein ebenes 2-dimensionales Grid
Algorithmus:
Wähle zwei zufällige Punkte im R²
Lege Gerade durch diese zwei Punkte
Erhöhe alle Punkte auf der eine Seite der Gerade,
erniedrige die auf der anderen um einen konstanten Wert
Wiederhole diese Schritte für eine vorher festgelegt Anzahl
von Iterationen
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
4
Fault Algorithmus
Pseudo-Code:
foreach(Iteration)
{
CreateRandomLine();
foreach( RowOfImage)
{
foreach(PixelOfRow)
{
processNewValue();
}
}
}
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
5
Fault Algorithmus
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
6
Variationen des Fault Algorithmus
Multiplikation der Geraden mit Sinus/Cosinus um weiche
Übergänge an den Kanten zu bekommen
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
7
Parallelisierung Fault Algorithmus
Algorithmus besteht aus drei for-Schleifen
Parallelisierung der Schleifen:
1.for-Schleife durchläuft Anzahl der Iterationen
mehrere Iterationen parallel möglich, da unabhängig
2.for-Schleife führt Berechung für jede Zeile im Bild aus
Parallelisierbar, da Zeilen unabhängig
3.for-Schleife arbeitet auf genau einer Zeile
Pro Zeile eine Grenze ( Schnittpunkt mit der Geraden),
Aufteilung in Teil der erhöht und der erniedrigt wird
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
8
Umsetzung in CUDA
Naiver Ansatz:
Laden des Grids in Global Memory
Threads arbeiten auf Daten im Global Memory
Probleme mit Nebenläufigkeit, Performance etc.
Optimierter Ansatz:
Aufteilung des Grids in Blöcke
Block in Shared Memory laden
Berechnung aller Iterationen für jeweiligen Block
Danach wieder zurück in Global Memory speichern
Weitere Optimierungen:
Coalesced Speicherzugriff der Threads
Zugriff auf Zufallzahlen über Constant Memory
-
Oder: Zufallszahlen auf der GPU erzeugen
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
9
Quellcode – Kernelaufruf
int CreateHeightMap()
{
CUT_DEVICE_INIT();
dim3 threads(TPL,ZPB);// 16 x 16
dim3 grid(WIDTH/BLOCKWIDTH,HEIGHT/ZPB); // 1k x 1k -> 64 x 8, bei 2k x 2k -> 128 x 16
int rand[ITERATIONS*4];
for(i=0;i<ITERATIONS*4;i++){
// rand[ ] mit Zufallszahlen füllen
}
CUDA_SAFE_CALL(cudaMemcpyToSymbol(rand_d, rand ,ITERATIONS*4*sizeof(int),0) );
GLfloat* HeightMap_d;
CUDA_SAFE_CALL(cudaMalloc((void**) &HeightMap_d, WIDTH*HEIGHT*sizeof(float)));
splitpicture<<<grid, threads>>>(HeightMap_d);
CUDA_SAFE_CALL(cudaMemcpy(HeightMap, HeightMap_d , WIDTH*HEIGHT*sizeof(float),
cudaMemcpyDeviceToHost) );
}
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
10
Quellcode – Kernel
extern __constant__ int rand_d[];
__global__ void splitpicture(GLfloat *HeightMap_d)
{
__shared__ float aRow[ZPB][SMB/ZPB]; // Init. mit default-Wert weggelassen
for(int i = 0; i < ITERATIONS; i++){
// Variableninitialisierung, random-Werte, „Wendestelle“ bestimmen
for(int a=0;a<((SMB/ZPB)/TPL);a++){
int rel_pos=threadIdx.x*(BLOCKWIDTH/TPL) + a;
aRow[threadIdx.y][rel_pos] +=4*faktor*((float)value)*(1-__sinf(phi)/WAVEWIDTH);
}
}
for(int j = 0; j < ((SMB/ZPB)/TPL); j++){
HeightMap_d[offset+threadIdx.y*WIDTH+threadIdx.x*(BW/TPL)+j] =
aRow[threadIdx.y][threadIdx.x*(BLOCKWIDTH/TPL)+j];
}
}
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
11
Probleme
CUDA-Kernel kann unter X-Linux leider nur max. 5sek
laufen, bevor er terminiert wird
der Komplexität der Aufgabe ist ein Ende gesetzt ;-)
Komischerweise klappts manchmal doch
ab und an stürzt auch die GPU ab
Bildgrößen müssen vielfache von Zweierpotenzen sein
Im Idealfall: sind Zweiterpotenzen
Ursprüngliche (naive) Implementierung hatte (im Vergleich
zur Finalen Version) nur mäßige Performanz
Man muss schon manchmal etwas genauer nachdenken
Dokumentation von CUDA teilweise ungenau
z.B. Shared Memory kann nicht voll ausgenutzt werden
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
12
Benchmarks - CPU
• CPU-Implementierung ( P4 – 3,0GHz )
Bildgröße
Iterationen
Laufzeit
MPixel/s
512x512
256
7,2s
9,32
1024x1024
256
28,7s
9,35
1024x1024
512
59,4s
9,04
1024x1024
1024
120,7s
8,90
1024x1024
2048
229s
9,38
1024x1024
4096
457,35s
9,39
2048x2048
4096
1834s
9,37
4096x4096
2048
~3700s
~9,37
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
13
Benchmarks - CUDA
• CUDA-Implementierung (GF 8800 GTX )
Bildgröße
512x512
1024x1024
1024x1024
1024x1024
1024x1024
1024x1024
2048x2048
2048x2048
2048x2048
4096x4096
4096x4096
3072x4096
Iterationen
256
256
512
1024
2048
4096
1024
2048
4096
1024
2048
2048
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
Laufzeit
0,015s
0,059s
0,118s
0,235s
0,47s
0,94s
0,92s
1,84s
3,68s
3,60s
7,20s
7,40s
MPixel/s
4473,92
4549,75
4549,75
4569,11
4569,11
4569,11
4668,44
4668,44
4668,44
4772,19
4768,21
3484,76
SpeedUp
480
486,44
503,39
513,62
487,23
486,54
497,83
498,37
498,37
509,72
513,46
372,55
14
Zusammenfassung
Auf der CPU teilweise nicht zumutbare Ausführungszeiten
Allerdings noch größere Problemgrößen lösbar als mit
CUDA, da kein Timeout
Primitive CUDA-Implementierung
Relativ schnell lauffähig
Speedup bereits zwischen 10 und 40
Endversion: Enormer Speedup von ~ 500
Bereits bei kleinen Eingabedaten
Sehr gut skalierend
Allerdings auch nur durch viel Arbeit erreichbar
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
15
Demo
Genug geredet, jetzt wird’s gezeigt!
Oder gibt’s bisher schon
Fragen?
Friedrich-Alexander-Universität Erlangen-Nürnberg
Hannes Stadler, Sebastian Graf
16