Diese Antwort besteht aus zwei Teilen (ich habe sie geschrieben). Ein Teil ist leicht zu quantifizieren, der andere ist empirischer.
Hardwareeinschränkungen:
Dies ist der leicht zu quantifizierende Teil. Anhang F des aktuellen CUDA-Programmierhandbuchs enthält eine Reihe von harten Grenzwerten, die die Anzahl der Threads pro Block begrenzen, die ein Kernelstart haben kann. Wenn Sie einen dieser Werte überschreiten, wird Ihr Kernel niemals ausgeführt. Sie können grob zusammengefasst werden als:
- Jeder Block kann nicht mehr als 512/1024 Fäden insgesamt ( Compute Capability 1.x oder 2.x und später jeweils)
- Die maximalen Abmessungen jedes Blocks sind auf [512,512,64] / [1024,1024,64] begrenzt (Berechnen Sie 1.x / 2.x oder höher).
- Jeder Block kann insgesamt nicht mehr als 8k / 16k / 32k / 64k / 32k / 64k / 32k / 64k / 32k / 64k-Register verbrauchen (Compute 1.0,1.1 / 1.2,1.3 / 2.x- / 3.0 / 3.2 / 3.5-5.2 / 5,3 / 6-6,1 / 6,2 / 7,0)
- Jeder Block kann nicht mehr als 16 KB / 48 KB / 96 KB gemeinsam genutzten Speicher belegen (Compute 1.x / 2.x-6.2 / 7.0).
Wenn Sie innerhalb dieser Grenzen bleiben, wird jeder Kernel, den Sie erfolgreich kompilieren können, ohne Fehler gestartet.
Leistungsoptimierung:
Dies ist der empirische Teil. Die Anzahl der Threads pro Block, die Sie innerhalb der oben beschriebenen Hardwareeinschränkungen auswählen, kann und wirkt sich auf die Leistung des auf der Hardware ausgeführten Codes aus. Das Verhalten jedes Codes ist unterschiedlich und die einzige Möglichkeit, ihn zu quantifizieren, besteht in einem sorgfältigen Benchmarking und Profiling. Aber noch einmal sehr grob zusammengefasst:
- Die Anzahl der Threads pro Block sollte ein rundes Vielfaches der Warp-Größe sein, die auf der gesamten aktuellen Hardware 32 beträgt.
- Jede Streaming-Multiprozessoreinheit auf der GPU muss über genügend aktive Warps verfügen, um die unterschiedliche Latenz der Speicher- und Befehlspipeline der Architektur ausreichend zu verbergen und einen maximalen Durchsatz zu erzielen. Der orthodoxe Ansatz besteht darin, eine optimale Hardware-Belegung zu erreichen (worauf sich Roger Dahls Antwort bezieht).
Der zweite Punkt ist ein großes Thema, von dem ich bezweifle, dass irgendjemand versuchen wird, es in einer einzigen StackOverflow-Antwort zu behandeln. Es gibt Leute, die Doktorarbeiten über die quantitative Analyse von Aspekten des Problems schreiben (siehe diese Präsentation von Vasily Volkov von der UC Berkley und diese Arbeit von Henry Wong von der University of Toronto für Beispiele, wie komplex die Frage wirklich ist).
Auf der Einstiegsebene sollten Sie sich vor allem darüber im Klaren sein, dass die von Ihnen gewählte Blockgröße (innerhalb des durch die obigen Einschränkungen definierten Bereichs zulässiger Blockgrößen) einen Einfluss darauf haben kann und hat, wie schnell Ihr Code ausgeführt wird, dies hängt jedoch von der Hardware ab Sie haben und den Code, den Sie ausführen. Beim Benchmarking werden Sie wahrscheinlich feststellen, dass der meiste nicht triviale Code einen "Sweet Spot" in den 128-512 Threads pro Blockbereich aufweist, aber es erfordert eine Analyse von Ihrer Seite, um herauszufinden, wo sich dieser befindet. Die gute Nachricht ist, dass der Suchraum sehr begrenzt ist und die beste Konfiguration für einen bestimmten Code relativ leicht zu finden ist, da Sie in Vielfachen der Warp-Größe arbeiten.
Die obigen Antworten zeigen auf, wie sich die Blockgröße auf die Leistung auswirken kann, und schlagen eine gemeinsame Heuristik für die Auswahl auf der Grundlage der Belegungsmaximierung vor. Ohne das Kriterium für die Auswahl der Blockgröße angeben zu wollen, ist zu erwähnen, dass CUDA 6.5 (jetzt in der Release Candidate-Version) mehrere neue Laufzeitfunktionen enthält, die bei der Belegungsberechnung und der Startkonfiguration helfen (siehe)
CUDA Pro-Tipp: Die Belegungs-API vereinfacht die Startkonfiguration
Eine der nützlichen Funktionen ist
cudaOccupancyMaxPotentialBlockSize
die heuristische Berechnung einer Blockgröße, die die maximale Belegung erreicht. Die von dieser Funktion bereitgestellten Werte könnten dann als Ausgangspunkt für eine manuelle Optimierung der Startparameter verwendet werden. Unten ist ein kleines Beispiel.BEARBEITEN
Das
cudaOccupancyMaxPotentialBlockSize
ist in dercuda_runtime.h
Datei definiert und wie folgt definiert:Die Bedeutung für die Parameter ist die folgende
Beachten Sie, dass ab CUDA 6.5 die eigenen 2D / 3D-Blockabmessungen aus der von der API vorgeschlagenen 1D-Blockgröße berechnet werden müssen.
Beachten Sie auch, dass die CUDA-Treiber-API funktional äquivalente APIs für die Belegungsberechnung enthält, sodass die Verwendung
cuOccupancyMaxPotentialBlockSize
im Treiber-API-Code auf die gleiche Weise möglich ist, wie sie im obigen Beispiel für die Laufzeit-API gezeigt wurde.quelle
Die Blockgröße wird normalerweise ausgewählt, um die "Belegung" zu maximieren. Suchen Sie nach CUDA-Belegung, um weitere Informationen zu erhalten. Siehe insbesondere die Tabelle zum CUDA-Belegungsrechner.
quelle