Hauptseminar MAP08 Random Heightmap on GPU Hannes Stadler, Sebastian Graf [email protected], [email protected] 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