Nvidia CUDA

NVIDIA CUDA (Compute Unified Device Architecture) ist eine von NVIDIA entwickelte parallele Computing-Plattform und ein Programmiermodell. CUDA ermöglicht es Entwicklern, hochleistungsfähige NVIDIA-GPUs (Graphics Processing Units) für allgemeine Computing-Aufgaben zu verwenden. Durch CUDA können Entwickler die leistungsstarken Computing-Fähigkeiten von GPUs für groß angelegte parallele Berechnungen nutzen und so die Anwendungsleistung erheblich verbessern, insbesondere in Bereichen wie wissenschaftliches Rechnen, maschinelles Lernen, Bildverarbeitung und physikalische Simulation. CUDA unterstützt mehrere Programmiersprachen wie C, C++ und Python und bietet eine umfassende Suite von Bibliotheken und Tools, die Entwicklern die einfache GPU-beschleunigte Berechnung ermöglichen.

cuda logo

Grundlagen der CUDA-Programmierung

Wie können wir GPU-Ressourcen in einem Programm aufrufen, um die Codeausführung zu beschleunigen? Durch die Verwendung von CUDA können wir leicht Tausende von Rechenkernen innerhalb der GPU verwalten. Das CUDA-Programmiermodell ist ein heterogenes Modell, das erfordert, dass CPU und GPU zusammenarbeiten. In der CUDA-Programmierung werden die Begriffe "Host" und "Device" verwendet, um die Geräte zu unterscheiden, auf denen der Code ausgeführt wird.

  • Host: CPU und Host-Speicher
  • Device: GPU und Videospeicher

Im Allgemeinen lädt das Hauptprogramm auf der CPU, kopiert dann die Initialisierungsdaten auf die GPU. Die GPU führt die Berechnungen durch und kopiert die Ergebnisse zurück auf die CPU.

Wir können einen Kernel in einem CUDA-Programm verwenden, um den oben genannten Prozess zu implementieren. In CUDA bezieht sich ein kernel auf eine Funktion, die bei Aufruf bewirkt, dass die GPU viele Threads gleichzeitig startet, um diesen Kernel auszuführen, wodurch Parallelität erreicht wird. Jeder Thread führt den Kernel unter Verwendung seiner Thread-ID aus, um dem Index der Eingabedaten zu entsprechen, wodurch sichergestellt wird, dass jeder Thread denselben Kernel ausführt, aber unterschiedliche Daten verarbeitet.

Die GPU hat eine enorme Anzahl von Rechenkernen, und CUDA verwendet eine zweistufige Organisationsstruktur zur Verwaltung dieser Kerne. Hier sind drei Konzepte in der CUDA-Programmierung, die eingeführt werden müssen: Thread, Block und Grid.

  • Thread: Ein paralleles CUDA-Programm wird von vielen Threads ausgeführt.
  • Block: Mehrere Threads werden zusammen zu einem Block gruppiert.
  • Grid: Mehrere Blöcke werden dann zu einem Grid zusammengefasst.

Hinweis: Threads innerhalb desselben Blocks können durch gemeinsamen Speicher synchronisieren und kommunizieren.

cpu and gpu

In CUDA hat jeder Thread einen eindeutigen Bezeichner namens ThreadIdx, der sich abhängig von der Art und Weise ändert, wie das Grid und der Block aufgeteilt werden.

Darüber hinaus finden Sie hier eine kurze Einführung in das CUDA-Speichermodell, wie im Diagramm unten gezeigt. Jeder Thread hat seinen eigenen privaten lokalen Speicher, während jeder Thread-Block gemeinsamen Speicher enthält, auf den alle Threads innerhalb des Blocks zugreifen können, mit einer Lebensdauer, die der des Thread-Blocks entspricht. Darüber hinaus können alle Threads auf den globalen Speicher zugreifen. Es gibt auch einige schreibgeschützte Speicherbereiche: konstanten Speicher und Texturspeicher. Die Speicherstruktur betrifft die Programmoptimierung, die hier nicht im Detail erläutert wird.

cpu and gpu

CUDA-Demonstrationsbeispiel

Jetzt erleben wir die GPU-Beschleunigung durch ein einfaches Beispiel. In diesem Beispiel berechnen wir die Summe zweier Vektoren sowohl auf der CPU als auch auf der GPU und vergleichen die Berechnungsgeschwindigkeiten zwischen CPU und GPU.

Vorbereiten der Laufzeitumgebung

Das JetPack-Betriebssystem enthält bereits die CUDA-Laufzeitumgebung. Wir können die CUDA-Version mit dem jtop-Tool überprüfen. Öffnen Sie das Terminal und führen Sie jtop aus.

bash
jtop

jtop

Hinweis: Wenn jtop nicht auf Ihrem System installiert ist, lesen Sie bitte diese Anleitung.

Im Folgenden werden wir Python verwenden, um CUDA-Code zu schreiben. Wir müssen daher den folgenden Befehl im Terminal ausführen, um Numba zu installieren.

bash
pip install numba

Ausführen des Beispielcodes

Schritt 1: Erstellen Sie ein Python-Skript für diesen Kurs im Stammverzeichnis:

bash
mkdir -p ~/reComputer_J/3.4_CUDA
touch ~/reComputer_J/3.4_CUDA/add_compare.py

Schritt 2: Öffnen Sie VSCode im Verzeichnis, in dem sich das Skript befindet:

bash
cd ~/reComputer_J/3.4_CUDA
code .

Schritt 3: In der linken Navigationsleiste können wir hello_world.py sehen. Geben Sie den folgenden Code in die Python-Datei ein:

Code zum Erweitern anklicken
python
from numba import cuda, float32
import numpy as np
import time


@cuda.jit
def add_gpu(a, b, out):
  tx = cuda.threadIdx.x
  ty = cuda.blockIdx.x
  block_size = cuda.blockDim.x
  grid_size = cuda.gridDim.x
  start = tx + ty * block_size
  stride = block_size * grid_size

  for i in range(start, a.shape[0], stride):
      out[i] = a[i] + b[i]

def add_cpu(a, b, out):
  for i in range(a.shape[0]):    
      out[i] = a[i] + b[i]

def main():
  # Prepare test data
  n = 10000000
  a = np.arange(n).astype(np.float32)
  b = np.arange(n).astype(np.float32)
  out = np.empty_like(a)

  # 1. Test CPU computation time
  start = time.time()
  add_cpu(a, b, out)
  print("CPU Time Taken:", time.time()-start)

  # 2. Test GPU computation time
  # Copy data from host memory to device memory
  d_a = cuda.to_device(a)
  d_b = cuda.to_device(b)
  d_out = cuda.device_array_like(out)
  # Define the number of threads per block and the number of blocks
  threads_per_block = 256  
  blocks_per_grid = (n + threads_per_block - 1) // threads_per_block
  # Compute the result
  start_gpu = time.time()
  add_gpu[blocks_per_grid, threads_per_block](d_a, d_b, d_out)
  end_gpu = time.time()
  # Copy the result from device memory back to host memory
  d_out.copy_to_host(out)

  print("GPU Time Taken:", end_gpu-start_gpu)


if __name__ == "__main__":
  main()

Schritt 4: Klicken Sie auf die Ausführen-Schaltfläche, um das Ergebnis des Python-Skripts im Terminal zu sehen.

launch vscode

Aus den im Terminal ausgegebenen Ergebnissen ist zu beobachten, dass die GPU-Berechnungsgeschwindigkeit schneller ist.

Weitere CUDA-Lernprogramme

TutorialTypBeschreibung
Getting Started with CUDA Programming(zh)DokumentEin minimalistisches Tutorial für den Einstieg in die CUDA-Programmierung auf Chinesisch
CUDA C++ Programming GuideDokumentDas Programmierhandbuch für das CUDA-Modell und die Schnittstelle.