======================= Erste Schritte mit CUDA ======================= Der typische Ablauf vieler Kernel-Aufrufe wie auch in der folgenden Aufgabe sieht so aus: * Speicher auf der GPU belegen mit Hilfe von `cudaMalloc`. Beispiel für einen Vektor `cuda_a` mit $N$ Elementen: ---- CODE (type=cpp) ------------------------------------------------------- double* cuda_a; CHECK_CUDA(cudaMalloc, (void**)&cuda_a, N * sizeof(double)); ---------------------------------------------------------------------------- * Daten von CPU-Speicher auf GPU-Speicher transferieren. Beispiel für das Kopieren des Vektors `a` im CPU-Speicher zum Vektor `cuda_a` im GPU-Speicher mit Hilfe von `cudaMemcpy`: ---- CODE (type=cpp) ------------------------------------------------------- CHECK_CUDA(cudaMemcpy, cuda_a, a, N * sizeof(double), cudaMemcpyHostToDevice); ---------------------------------------------------------------------------- * Aufruf der Kernel-Funktion. Hierbei sollte die Gesamtgröße sinnvoll auf Blöcke aufgeteilt werden. In erster Näherung sind 128 oder 256 Threads pro Block sinnvoll. Beispiel: ---- CODE (type=cpp) ------------------------------------------------------- unsigned int threads_per_block = 128; /* a multiple of the warp size */ unsigned int num_blocks = (N + threads_per_block - 1) / threads_per_block; axpy<<>>(N, 2.0, cuda_a, 1, cuda_b, 1); ---------------------------------------------------------------------------- * Rücktransfer der Ergebnisse. Hier ist bei `cudaMemcpy` die Richtungsangabe `cudaMemcpyDeviceToHost` zu verwenden: ---- CODE (type=cpp) ------------------------------------------------------- CHECK_CUDA(cudaMemcpy, a, cuda_a, N * sizeof(double), cudaMemcpyDeviceToHost); ---------------------------------------------------------------------------- * Freigabe des GPU-Speichers: ---- CODE (type=cpp) ------------------------------------------------------- CHECK_CUDA(cudaFree, cuda_a); ---------------------------------------------------------------------------- Aufgabe ======= Entwickeln Sie einen CUDA-Kernel `scal`, der einen Vektor `x` mit `n` Elementen skaliert: $\vec{x} \leftarrow \alpha \vec{x}$. Schreiben Sie dazu ein kleines Testprogramm, das einen Vektor im CPU-Speicher anlegt, initialisiert, zur GPU transferiert, dann die Kernel-Funktion aufruft, das Ergebnis wieder zurückholt und ausgibt. Das Makro `CHECK_CUDA` findet sich in der Header-Datei ``, die unter `/home/numerik/pub/hpc/session24` in der Vorlesungsbibliothek zur Verfügung steht. So kann Ihr Programm auf der Hochwanner übersetzt werden: ---- CODE (type=sh) ----------------------------------------------------------- nvcc -o scal -I/home/numerik/pub/hpc/session24 --gpu-architecture compute_20 scal.cu ------------------------------------------------------------------------------- :navigate: up -> doc:index next -> doc:session24/page02