Comprendre les dimensions de la grille CUDA, les dimensions de bloc et les fils organisation (explication simple) [fermé]

StackOverflow https://stackoverflow.com/questions/2392250

  •  25-09-2019
  •  | 
  •  

Question

Comment sont organisés les discussions à exécuter par un GPU?

Était-ce utile?

La solution

Matériel

Si un périphérique de GPU a, par exemple, 4 unités multiprocesseurs, et ils peuvent exécuter 768 threads chacun: puis à un moment donné plus de 4 * 768 threads seront vraiment en cours d'exécution en parallèle (si vous avez prévu plusieurs threads, ils sera attendant leur tour).

Logiciel

fils sont organisés en blocs. Un bloc est exécuté par une unité de multitraitement. Les fils d'un bloc peuvent être identifiées (indexé) en utilisant 1Dimension (x), 2Dimensions (x, y) ou les indices 3DIM (x, y, z) mais en tout cas x y z <= 768 pour notre exemple (d'autres restrictions à x, y, z, consultez le guide et votre capacité de l'appareil).

De toute évidence, si vous avez besoin de plus de ces 4 * 768 sujets dont vous avez besoin de plus de 4 blocs. Les blocs peuvent être indexés également 1D, 2D ou 3D. Il y a une file d'attente de blocs en attente d'entrer le GPU (parce que, dans notre exemple, le GPU dispose de 4 multiprocesseurs et seulement 4 blocs sont étant exécutée simultanément).

Maintenant, un cas simple: traitement d'une image 512x512

Supposons que nous voulons un fil pour traiter un pixel (i, j).

On peut utiliser des blocs de 64 fils chacun. Ensuite, nous avons besoin de 512 * 512/64 = 4096 blocs (De sorte à avoir 512x512 threads = 4096 * 64)

Il est fréquent d'organiser (pour rendre plus facile l'indexation de l'image) des fils dans les blocs 2D ayant blockDim = 8 x 8 (64 fils par bloc). Je préfère appeler threadsPerBlock.

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

et 2D gridDim = 64 x 64 blocs (les 4096 blocs nécessaires). Je préfère appeler numBlocks.

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

Le noyau est lancé comme ceci:

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

Enfin: il y aura quelque chose comme « une file d'attente de 4096 blocs », où un bloc est en attente d'être attribué l'un des multiprocesseurs du GPU pour obtenir ses 64 threads exécutés

.

Dans le noyau du pixel (i, j) à traiter par un fil est calculée ainsi:

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

Autres conseils

Supposons un GPU 9800GT: 14 multiprocesseurs, chacun a 8 threadprocessors et warpsize est de 32 ce qui signifie que chaque threadprocessor gère jusqu'à 32 fils. 14 * 8 * 32 = 3584 est le nombre maximal de fils de actuall cuncurrent.

si vous exécutez ce noyau avec plus de 3584 fils (disons 4000 fils et il est pas important comment vous définissez le bloc et la grille gpu les traiterez comme le même.):

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

alors l'ordre d'exécution de ces deux fonctions sont les suivantes:

1.func1 est exécutée pour les premiers fils 3584

2.func2 est exécutée pour les premiers fils 3584

3.func1 est exécutée pour les fils restants

4.func2 est exécutée pour les fils restants

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top