A CUDA programozási nyelv

Példaprogramok

Elemi CUDA program

A legelemibb CUDA program nem más, mint egy kernelhívás. Lássuk is ezt egy példán keresztül:
global void kernel() { } int main() { kernel<<< 1; 1 >>>(); return 0; }
Ez a program mindössze annyit csinál, hogy egy szimpla egyetlen szálat tartalmaz ó kernelt elindít a GPU-n, ami mivel nem tartalmaz semmit, azonnal vissza is tér, az alkalmazás futása pedig ezután véget ér. Na de következzen valami értelmesebb alkalmazás.

Szerzõ: Forster Richárd
Év: 2011
Környezet:

Adatmozgatás GPU és CPU között

A hivatalos NVIDIA dokumentációk terminológiájának megfelelõen ettõl kezdve a példákban a GPU-ra device néven, míg a CPU-ra host néven fogunk hivatkozni. Lássunk is rögtön egy példát az adatmozgatásra:
#include <iostream> using namespace std; global void kernel(int* d adatok) { *d adatok += *d adatok; } int main() { int *h adatok, *d adatok; h adatok = (int*)malloc(sizeof(int)); cudaMalloc(&d adatok,sizeof(int)); *h adatok = 10; cudaMemcpy(d adatok,h adatok,sizeof(int),cudaMemcpyHostToDevice); kernel<<< 1; 1 >>>(d adatok); cudaMemcpy(h adatok,d adatok,sizeof(int),cudaMemcpyDeviceToHost); cout << *h adatok; free(h adatok); cudaFree(d adatok); return 0; }
A memóriák közötti másolás iránya a másolást végzõ függvény utolsó paraméterétõl függ. Ha a hostról a devicera akarunk másolni, akkor a cudaMemcpyHostToDevice paramétert kell megadnunk negyedikként, míg fordított esetben a cudaMemcpyDeviceToHost-ot. Ekkor az irányoknak megfelelõen az elsõ két változó típusa is változik.
A program egyetlen szám, a 10-es kétszeresét számolja GPU-n és adja vissza az eredményt, tehát 20-at.

Szerzõ: Forster Richárd
Év: 2011
Környezet:

Párhuzamos GPU program

Lássuk hát a lényeget, egy valódi többszálú GPU alkalmazást.
#include <iostream> using namespace std; global void kernel(int* d adatok) { int index = blockIdx.x*blockDim.x+threadIdx.x; d adatok[index] *= d adatok[index]; } int main() { int *h adatok, *d adatok; h adatok = (int*)malloc(sizeof(int)*10); cudaMalloc(&d adatok,sizeof(int)*10); for(int i = 0 ; i < 10 ; ++i) h adatok[i] = i+1; cudaMemcpy(d adatok,h adatok,sizeof(int)*10,cudaMemcpyHostToDevice); kernel<<< 1; 10 >>>(d adatok); cudaMemcpy(h adatok,d adatok,sizeof(int)*10,cudaMemcpyDeviceToHost); for(int i = 0 ; i < 10 ; ++i) cout << h adatok[i]; free(h adatok); cudaFree(d adatok); return 0; }

Forráskód letöltése

Az alkalmazás célja, hogy veszi a számokat 1-tõl 10-ig és párhuzamosan kiszámolja mindegyiknek a négyzetét. Vegyük észre, hogy az elõzõ programhoz képest a main függvény csupán az adatok számában, annak feltöltési módjában, a kernel folyamatszámában, valamint a másoláskor átmozgatandó adatok mennyiségében különbözik. Jelen esetben minden 10 számunk van, így 10 folyamat kerül létrehozásra. A kernel maga egy plusz sorral b®vült, mely a gridben szereplõ blokkokból és az azon belüli folyamatok indexe alapján kiszámolja, hogy ez hanyadik szál az összes közül. Ennek segítségével a folyamat indexével tudunk hivatkozni az átadott adatokra is, például az elsõ szál az elsõ elemnek veszi a négyzetét, a tizedik, a tizedikét, stb.

Szerzõ: Forster Richárd
Év: 2011
Környezet: