nvidia nvidia - Comprendere le dimensioni della griglia CUDA, le dimensioni dei blocchi e l'organizzazione dei thread(spiegazione semplice)





download toolkit (3)


Supponiamo che una GPU 9800GT: 14 multiprocessori, ognuno ha 8 threadprocessors e warpsize 32, il che significa che ogni thread processor gestisce fino a 32 thread. 14 * 8 * 32 = 3584 è il numero massimo di filettature contemporanee.

se si esegue questo kernel con più di 3584 thread (ad esempio 4000 thread e non è importante la definizione del blocco e della griglia, gpu li tratterà allo stesso modo):

func1();
__syncthreads();
func2();
__syncthreads();

quindi l'ordine di esecuzione di queste due funzioni è il seguente:

1.func1 viene eseguito per i primi 3584 thread

2.func2 viene eseguito per i primi 3584 thread

3.func1 viene eseguito per i thread rimanenti

4.func2 viene eseguito per i thread rimanenti

Come sono organizzati i thread per essere eseguiti da una GPU?




Hardware

Se un dispositivo GPU dispone, ad esempio, di 4 unità di multiprocessing e possono eseguire 768 thread ciascuno: quindi in un dato momento non verranno eseguiti più di 4 * 768 thread in parallelo (se si pianificano più thread, saranno in attesa il loro turno).

Software

i thread sono organizzati in blocchi. Un blocco viene eseguito da un'unità multiprocessing. I thread di un blocco possono essere identificati (indicizzati) usando 1Dimension (x), 2Dimensioni (x, y) o indici 3Dim (x, y, z) ma in ogni caso x y z <= 768 per il nostro esempio (si applicano altre restrizioni a x, y, z, vedere la guida e le funzionalità del dispositivo).

Ovviamente, se hai bisogno di più di quei thread 4 * 768 hai bisogno di più di 4 blocchi. I blocchi possono anche essere indicizzati 1D, 2D o 3D. C'è una coda di blocchi in attesa di entrare nella GPU (perché, nel nostro esempio, la GPU ha 4 multiprocessori e solo 4 blocchi vengono eseguiti simultaneamente).

Ora un caso semplice: elaborare un'immagine 512x512

Supponiamo di volere un thread per elaborare un pixel (i, j).

Possiamo usare blocchi di 64 thread ciascuno. Quindi abbiamo bisogno di 512 * 512/64 = 4096 blocchi (in modo da avere 512x512 thread = 4096 * 64)

È comune organizzare (per semplificare l'indicizzazione dell'immagine) i thread in blocchi 2D con blockDim = 8 x 8 (i 64 thread per blocco). Preferisco chiamarlo threadsPerBlock.

dim3 threadsPerBlock(8, 8);  // 64 threads

e 2D gridDim = 64 x 64 blocchi (i 4096 blocchi necessari). Preferisco chiamarlo numBlocks.

dim3 numBlocks(imageWidth/threadsPerBlock.x,  /* for instance 512/8 = 64*/
              imageHeight/threadsPerBlock.y); 

Il kernel è lanciato in questo modo:

myKernel <<<numBlocks,threadsPerBlock>>>( /* params for the kernel function */ );       

Infine: ci sarà qualcosa come "una coda di 4096 blocchi", in cui un blocco attende l'assegnazione di uno dei multiprocessore della GPU per ottenere l'esecuzione dei 64 thread.

Nel kernel il pixel (i, j) da elaborare da un thread viene calcolato in questo modo:

uint i = (blockIdx.x * blockDim.x) + threadIdx.x;
uint j = (blockIdx.y * blockDim.y) + threadIdx.y;



Al momento, i chip grafici Intel non supportano CUDA. È possibile che, nel prossimo futuro, questi chip supportino OpenCL (che è uno standard molto simile a CUDA), ma questo non è garantito e anche i loro driver attuali non supportano OpenCL. (È disponibile un SDK Intel OpenCL, ma al momento non consente l'accesso alla GPU.)

I più recenti processori Intel (Sandy Bridge) hanno una GPU integrata nel core della CPU. Il tuo processore potrebbe essere una versione precedente, nel qual caso la "Intel (HD) graphics" è un chip indipendente.





cuda nvidia