Tipps & Tricks für den erfolgreichen Einsatz von GPU-Computing

801 views
744 views

Published on

Folien des Vortrags auf der parallel 2014. Neben den Grundlagen der Architektur von Grafikkarten werden die Besonderheiten bei der Parallelisierung von GPU-Kerneln erklärt. Anhand des Werkzeugs "Guided Application Analysis" des Nvidia Visual Profiler werden Tipps und Tricks für die Optimierung gegeben und der theoretische Hintergrund erläutert. Es wird gezeigt, wie mit Streaming und dem Einsatz von mehreren GPUs (Multi-GPU) Systeme besser ausgelastet werden können. Der Referent stellt hierbei Klassen und Hilfsmittel vor, die er bei der Projektarbeit im Bereich GPU Computing in den letzten fünf Jahren erlernt hat.

Published in: Software
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
801
On SlideShare
0
From Embeds
0
Number of Embeds
166
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Tipps & Tricks für den erfolgreichen Einsatz von GPU-Computing

  1. 1. Tipps & Tricks für den erfolgreichen Einsatz von GPU-Computing 5. Mai 2014 Jörn Dinkla Version 1.0
  2. 2. Motivation
  3. 3.  Angekündigt  „In diesem Vortrag wird ein sequenzielles Programm schrittweise in ein optimiertes massiv-paralleles GPU-Programm überführt…“  Aber  CUDA 6.0  Optimierungsergebnisse Kepler  Didaktisch nicht geeignet  Zu viel Fachlogik, zu wenig GPU  Daher  mehrere kleine Programme, aber mehr GPU Klärung
  4. 4.  Folien und Sourcecode gibt es unter ... http://dinkla.net/parallel2014 Download
  5. 5.  Tablet, PC, Großrechner, Cloud, Spielkonsole, Autos … GPU-Computing überall
  6. 6.  Vom Modell zum Bild ... Computer-Grafik Tomas Akenine-Mőller © 2002, Quelle: http://www.realtimerendering.com/
  7. 7. Programmierbare Shader
  8. 8. Massiv Parallel
  9. 9. Kepler GK 110
  10. 10.  Z. B.  NVIDIA Tesla  AMD FirePro  Eigenschaften  ECC Speicher  Größerer Speicher  Bessere Double-Performance  Kein Monitor-Anschluss  Keine Kühlung Auch spezielle Karten
  11. 11. C ++ 11 C ++ C Frameworks Device WDDM Framework CUDA OpenCL C++ AMP DirectX AMDTreiber TDD Thrust C++- Wrapper Library
  12. 12.  CUDA ⊖ Benötigt NVIDIA-Hardware ⊕ Teilweise C++ ⊕ Am meisten benutzt  C++ AMP ⊖ Benötigt Windows/DirectX, Einschränkungen ⊖ Noch „jung“, keine erprobten Libraries ⊕ C++ 11  OpenCL ⊖ Geringer Abstraktionsgrad, C99 ⊖ Nicht so viele Libraries wie bei CUDA ⊕ Apple, Intel, AMD Einschränkungen
  13. 13.  Schnelle erste Erfolge  2x – 5x Speedup  Dann wird es schwieriger …  Wissen über die Hardware notwendig Speedup 2 3 4 5 6 7 8 9 10 11 …
  14. 14.  Schneller, Größer, Besser  Nur wenn notwendig! Parallelisieren? 1080p Ultra HD / 4K720p576p480p
  15. 15.  Nicht das Rad neu erfinden  „best practices“  „think parallel“  Empfehlung:  „Structured Parallel Programming“  Michael McCool et. al.  Intel-lastig, Cilk Plus, TBB Parallele Patterns
  16. 16. Parallele Patterns Siehe http://www.parallelbook.com/
  17. 17. map (*2) [1..1024] = [2,4,…,2048] Datenparallelität: Map Index 0 1 2 3 4 5 6 7 … 1023 Wert 1 2 3 4 5 6 7 8 … 1024 Ergebnis 2 4 6 8 10 12 14 16 … 2048
  18. 18. Mit Thrust
  19. 19. Mit C++ AMP Lambda-Ausdruck: [bindings](params) { body; }
  20. 20.  Bolt  Ähnlicher Abstraktionsgrad  Leider nur für AMD  Projekt nicht aktiv  C++-Bindings  C++ (Nicht C++ 11)  Siehe „Schneller Einstieg in OpenCL mit C++-Bindings“ OpenCL
  21. 21.  Abstraktion wichtig für Fortschritt  Java, JVM, Web-Frameworks mit Ruby  Rapid Prototyping  Aber:  Hintergrundwissen bei GPU-Computing notwendig!!!  Was ist hinter dem „Vorhang“ des APIs?  Die beiden Programme haben einen Unterschied! Wer findet ihn? Schöne neue Welt
  22. 22. Device Kernel sequence d Kernel transform Host d‘ d d Device Kernel transform Host v av av v iota v Beispiel mit thrust (konstruiert, muss nicht so sein!) Beispiel mit C++ AMP (konstruiert, muss nicht so sein!)
  23. 23. Host Host und Device CPU 1 Core Global Memory Bus GPU / Device Mem. Ctrl. Prozessor (SM) C CC C C CC C C CC C Core Core Core Global Memory 8/16
  24. 24. Host und Device  Host  Der „Kopf“ des Ganzen  Management  Speicher, Queues, Events  Aufruf von Kerneln  Synchronisation  Device  Traditionell „reine Arbeitspferde“
  25. 25.  Basis: BaseBuffer  HostBuffer  Unpinned  Pinned (nicht swapbar)  Lokaler Speicher (NUMA)  DeviceBuffer Buffer
  26. 26.  Host- und Device-Buffer  Versionierung der beiden Seiten  get_host()->incr_version()  Aktualisierung je nach Version  update_host()  update_device()  CUDA 6: Unified Memory BufferPair Host Buffer Device Buffer
  27. 27. 1. Übergebe ID als Parameter 2. Hole Daten anhand ID 3. Verarbeitung 4. Speichere Daten anhand ID SPMD / SIMT
  28. 28.  Kernel ruft Funktion op auf  Index-Berechnungen extern Back to the Basics
  29. 29.  Größe / Extension  width, height, depth  index(x,y,z)  in_bounds(x,y,z)  int checked_index(x,y,z) Extent 0 1 2 3 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 2 3
  30. 30. Grund: Kernel in der Praxis Aus Wilt „The CUDA Handbook“, S. 218 „Index- Schlacht“ OptimiertNachteil: Speicherorganisation fest verdrahtet
  31. 31.  Vor dem Kernel-Aufruf  Wechsel der Abstraktionsebene  Host zu Device  Von C++-Datenstrukturen zu Device-Pointern Aufruf des Kernels Kernel-Aufruf
  32. 32.  Größe des Thread-Block  Für Performance wichtig  Hängt von Hardware ab  Zerlegung der Eingabedaten  Thread-Block, Work group, Tile  Grid, NDRange  Beispiel  Daten 8x8  Grid 2x2  Block 4x4  NestedExtent Grid = Data/Block 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 Daten, Pixel, Voxel Grid
  33. 33.  kernel<<<g, tb, sm, s>>>(params)  Kernel-Konfiguration  dim3 Grid g  dim3 Thread-Block tb  Größe des Shared-Memory sm  cudaStream_t s  Oft abhängig vom Extent  CudaExecConfig(Extent& e) CudaExecConfig
  34. 34.  Benchmark mit folgenden Funktor  und verschieden Block-Größen Blockgröße und Performance
  35. 35.  Magische 32! Optimum 128? Warum? Unterschiedlichen Laufzeiten Anzahl Threads Zeit [ms] 1 686,449 2 333,055 3 222,076 4 166,660 5 133,771 16 42,532 32 21,878 64 12,491 96 9,269 128 8,306 192 8,937 256 8,617 512 8,476 768 10,123 1024 8,563
  36. 36.  Ein Thread-Block wird einem festen SM zugewiesen  Zerlegung eines Blocks in Warps  32 Threads pro Warp  Kleinste Scheduling-Einheit Thread-Block-Größe  Vielfaches von 32 Grund: Warp
  37. 37.  CUDA  Nsight (Visual Studio, Eclipse)  Visual Profiler (Eclipse)  Kommandozeile nvprof  OpenCL  Intel Vtune (*)  AMD CodeXL  C++ AMP  Visual Studio 2013 Profiling
  38. 38.  Computation Bound  Alle Prozessoren 100% ausgelastet  Memory Bound  Bandbreite zum Speicher voll ausgelastet  Latency Bound  Warten auf die Daten Arten der Auslastung
  39. 39.  Sortiert nach Optimierungspotential NVVP‘s Guided Analysis Hier!
  40. 40. Memory Bound
  41. 41. Host Verschiedene Speicher CPU 1 Core L1 / L2 Core L1 / L2 L3 Cache Global Memory Bus GPU Global Memory Constant Texture Prozessor (SM) Local / Shared / L1 Registers C CC C L2 Cache 8/168-20 192/ 288 1600 8000 Mem. Ctrl.
  42. 42. 128 Kerne sind Optimum
  43. 43.  Einfaches Beispiel, überraschendes Ergebnis  128 Optimum, aber 192 Kerne  „Viel hilft viel“ stimmt hier nicht  Kernel-Konfiguration  Anzahl der Threads = 32*k  Benchmarks notwendig! Fazit
  44. 44.  Lesezugriffe und Schreibzugriffe  Anzahl, Datenmenge, Zugriffsmuster  Operationen  Komplexität pro Element / Granularität  O(1)  O(log n)  O(n)  O(n^2)  In der Regel memory bound aber evtl. computation bound Performance einer Map
  45. 45. Mandelbrot-Kernel
  46. 46. Benchmark Thread-Block Laufzeit [ms] 32, 4 2444,86 64, 4 2453,58 32, 6 2453,65 64, 2 2457,14 32, 5 2465,33 192, 2 2469,59 128, 1 2476,28 64, 3 2479,65 96, 3 2480,85
  47. 47.  Occupancy Unterschiede? Profilen! Limiter!
  48. 48.  Max. 16 Thread-Blöcke „resident“ (*)  Einer aktiv (dunkelgrün)  Ready to go (hellgrün)  Wartend auf Speicher (orange)  Z. B. Occupancy 5/8 = 62.5% Latency Hiding W0SMX W1 W2 W3 W4 -- -- --
  49. 49.  Berücksichtige (Werte für CC 3.5)  Max Threads pro Block 1024  Max Blocks pro SMX 16  Max Warps pro SMX 64  Max Threads pro SMX 2048  Anzahl 32-bit Register pro SMX 64K  Max Anzahl Register pro Thread 255  Max Shared Mem pro SMX 48 KB  Max Shared Mem pro Block 48 KB Occupancy ist komplex
  50. 50. Occupancy Calculator
  51. 51.  128 Threads pro Block  16 Thread-Blöcke pro SMX  2048 Threads pro SMX  192 Threads pro Block  Passen nur 10 TB / SMX  Insg. 1920 Threads pro SMX  Denn 11*192 = 2112 > 2048 128 besser als 192
  52. 52.  Computation bound Guided Analysis
  53. 53.  1204,75 GFLOPS Erreichte Performance
  54. 54.  Inhärent sequentiell wg. while Weitere Optimierung?
  55. 55.  ABER:  Laut Werbung: 3977 GFLOPS (GTX 780)  Volle Auslastung einer GPU  Alle Kerne auf allen SMX bearbeiten eine FMA, d.h. warten nicht auf den Speicher  FLOPS = Anzahl der Kerne * Takt * 2  780er: 2304 * 863 Mhz * 2  FMA („Fused multiply-add“) zählt als zwei Operationen Theoretisches Maximum
  56. 56.  Schleifen  Integer-Berechnungen  Speicher-Zugriffe  „Instruktions-Mix“ … schwer zu erreichen
  57. 57.  Vergleich 5k*5k, 1000 MaxIter Prozessor Intel Core i7 3820 3.7 GHz Intel Core i7 4960HQ 2.60GHz EVGA 780, 967 MHz Base, 1020 MHz Boost Laufzeit [ms] 24.249 20.784 39,605 Faktoren Faktoren Faktoren 1 Kern 612,271 524,782 1,000 4 Kerne 153,068 131,196 8 Kerne 76,534 65,598 12 Kerne 51,023 43,732 16 Kerne 38,267 32,799 Vergleich mit CPUs
  58. 58.  Kopie zum Device?  Pro Node eine Kopie? Performance? Hierarchische Datenstrukturen
  59. 59.  Möglichkeit  Eigene Speicherverwaltung  Ein Array  new überladen  int index  Statt Pointer  Eine Kopie Hierarchische Datenstrukturen
  60. 60. cudaMallocManaged()
  61. 61.  Suche nach 1…7 in Baum Parallele Baumsuche 4 2 6 7531
  62. 62. Parallele Baumsuche
  63. 63.  Single Instruction!!!  Mask-Bit für jeden Thread im Warp SIMT - Divergenz 0 1 2 3 int tid = treadIdx.x; if (tid < 2) { call_expensive_function() } else { call_expensive_function2() } Warps Code
  64. 64. Divergenz Divergenz
  65. 65.  While-Schleife statt Rekursion  Keine Divergenz mehr! Verbesserung
  66. 66.  „Dynamic Parallelism“  Ab CC 3.5, CUDA 5.5 Rekursive Kernel
  67. 67.  Einschränkungen  Stack-Frames benötigen Speicherplatz  Rekursionstiefe beschränkt Rekursive Kernel
  68. 68.  Wenig Elemente „Sparse“ Daten 0 1 2 3 4 5 6 7 0 1 2 3 Divergenz
  69. 69.  Komprimieren!  Daten liegen „dicht“  „Keine“ Divergenz mehr!  Minimierung von Kopien! Pack / Expand 0 1 2 3 4 5 6 7 0 1 0 1 0 0 1 1 1 5 2 2 3 6 3 3 1 2
  70. 70.  Maximiere in dieser Reihenfolge 1. Parallelität 2. Speicherdurchsatz 3. Berechnungsdurchsatz Anleitung: Optimierung
  71. 71. Maximiere Parallelität Kerne CPUs GPUs SMXs Kerne
  72. 72.  Wegen Kopien  Auf dem Device behalten? Auslastung gering
  73. 73.  Überlappung: Kopie und Kernel Möglichkeit: Streaming
  74. 74.  Kopien müssen asynchron sein  cudaMemcpyAsync(…,stream)  Kernel bekommen Argument  kernel<<<g, b, sm, stream>>>(…)  Synchronisation  Nur, wenn notwendig  cudaStreamSynchronize Streaming
  75. 75.  Aufwand  Umstellen des Codes  Einfügungsreihenfolge  HyperQ ab CC 3.5  Bei CC<3.5  Achtung Performance  Auf richtige Reihenfolge achten  Siehe Literatur  Synchronisation über Events Streaming
  76. 76.  Einsatz mehrerer GPUs  Explizite Auswahl des Devices  CUDA: cudaSetDevice()  OpenCL: clCreateContext()  C++ AMP: accelerator_view als Argument zu parallel_for_each Multi-GPU
  77. 77.  Kernel und Speicher auf gleichem Device!  => Partionierung / Strategie  Datenstruktur für Zuordnung  map<partition, device>  Vorsicht bei Bibliotheken  Z. B. Thrust  Bisher nicht komfortabel gelöst Anforderungen
  78. 78. Multi-GPU
  79. 79.  Steuerung durch den Host  Möglichkeiten 1. Ein Thread füllt alle Streams 2. Pro GPU ein Thread für zwei Streams 3. Pro Stream ein Thread  Performance ist systemabhängig Multi-GPU
  80. 80. OpenMP Warte OpenMP
  81. 81.  CPUs nutzen  Auslastung der GPU  Parallele Kernel  Streams  Auslastung der SMs  Thread-Block  Occupancy  Auslastung der Kerne  „Instruction level parallelism“ (ILP) Maximiere Parallelität
  82. 82.  Minimiere Synchronisation  Innerhalb Thread-Block  __syncthreads()  Atomare Zugriffe  atomicAdd()  Speicher  Zwischen Kernel-Aufrufen Maximiere Parallelität
  83. 83.  On-Chip-Speicher  Register, Shared/Local  Cache  Spezial-Speicher  Konstanter Speicher, Texturspeicher  Device-Speicher  Minimiere Kopien  „Coalesced“ Transaktionen Max. Speicherdurchsatz
  84. 84.  Transaktionen sind immer 32, 64 oder 128 Byte  Innerhalb eines Warps  „Zusammengefasst“  „Coalesced“ Speicherdurchsatz 31 63 95 127 159 191 223 255 287 319 351 383
  85. 85.  y- statt x-Richtung Speicherdurchsatz 31 63 95 127 159 191 223 255 287 319 351 383
  86. 86.  Minimiere Divergenz  Loop-Unrolling  Berechnen statt Speichern  Arithmetik –fast_math  Präzision vs. Geschwindigkeit  Fusion von Kerneln Max. Berechnungen
  87. 87.  Heuristiken, keine Patentrezepte  Bisher Unterschiede bei jeder Karten-Generation  Benchmarks sind Pflicht!  Neugierde auch!  Literatur ist inzwischen reichlich vorhanden Fazit
  88. 88.  Einsteiger  „CUDA by Example“  Sanders, Kandrot  Fortgeschritten  CUDA Programming  Cook  CUDA Handbook  Wilt CUDA
  89. 89.  Spezialisten  GPU Computing Gems  „Jade“ und „Emerald“  Doku  „Programming Guide“  „Best Practices Guide“  Web  CudaZone bei nvidia.com  Parallel Forall (Blog)  Dokumentation docs.nvidia.com CUDA
  90. 90.  Einsteiger/Fortgeschritten  „… in Action“  „… Programming Guide“  „Heterogenous Computing with OpenCL“  Web  Khronos  AMD‘s OpenCL Zone  Apple / Mac OS X OpenCL
  91. 91.  Bisher nur ein Buch  „C++ AMP“  Web  Microsoft  Intel‘s Prototyp/PoC „Shevlin Park“ C++ AMP
  92. 92.  Bin beide Tage vor Ort  Sprechen Sie mich an!  joern@dinkla.com  Ansonsten  Happy GPU-Computing! Fragen ?
  93. 93.  Freiberuflicher Dipl.-Inform.  Schwerpunkte  Parallele Systeme  C++ und Java/JVM  GPU-Computing  CUDA, OpenCL, C++ AMP  Weitere Informationen  http://www.dinkla.net Last but not least

×