CUDA paralleles Programmieren

N-mal Funktion parallel ausführen

__global__ void add( int *a, int *b, int *c){
.      *c = *a + *b;
}

// Funktion add() wird 1-mal ausgeführt
add<<< 1, 1 >>>( dev_a, dev_b, dev_c );

// Funktion add() wird N-mal ausgeführt
add<<< N, 1 >>>( dev_a, dev_b, dev_c );

Die Variablen werden dadurch zu Arrays.
a -> a[N]      ,       b -> b[N],        c -> c[N]


Zugreifen auf die parallelen Prozesse

Jeder parallele Prozess läuft im Kernel in einem anderen Block. Jeder Block hat seine Id  blockIdx.x  .
a[1], b[1], c[1] laufen im Block 1.

c[0] = a[0] + b[0]
__global__ void add( int *a, int *b, int *c ) {
.      c[blockIdx.x] = a[blockIdx.x] + b[blockIdx.x];
}

.

CUDA Threads

Eine Funktion kann N-mal aufgerufen werden. Daraus entstehen N parallele Blocks im Kernel, die man über ihre Block-Id ansprechen kann.

Innerhalb eines Blocks können mehrere Prozesse (Threads) gestartet werden. Dies ist notwendig, wenn ein Vektor, auf mehrere Blöcke eingeteilt wird.
Jeder Block hat seinen Vektor. Doch innerhalb eines Vektors entstehen mehrere Prozesse.

__global__ void add( int *a, int *b, int *c ) {
.   c[ threadIdx.x blockIdx.x ] = 
.              a[ threadIdx.x  blockIdx.x ] + 
.              b[ threadIdx.x  blockIdx.x ];
}

Jedes Element des Vektors hat seinen Thread.

 

CUDA Threads and Blocks

Einfaches Handling in Cuda
Cuda ist spezialisert auf das parallele Verarbeiten vieler Elemente (Vektoren).

Bsp:
8 Blocks (Funktion wird 8 mal ausgeführt) mit
Vektoren in der Funktion.
Jedes Element des Vektors kann per Thread-Index angesprochen werden.

threads_block

Zugriff auf ein Element
Der Index des Elements ist einfach gebildet

int index = (blockIdx.x * Blocktiefe) + threadIdx.x
int index = (blockId2.2 * 8) + threadId5.5
int index = ( 2 * 8 ) + 5 = 21

index_cuda
Elemente aus verschiedenen Threads und Blocks
Sofern man genau weiss, wie weit die Daten in den einzelnen Threads generiert sind, können Indizes unterschiedlicher Nummern verarbeitet werden

__global__ void add( int *a, int *b, int *c ) {

.      c[index12] = a[index63] + b[index20];
}

Dazu braucht es jedoch die Synchronisation der Prozesse, die über synctrheads() organisiert werden kann.