Comment les blocs / warps / threads CUDA mappent-ils sur les cœurs CUDA?


143

J'utilise CUDA depuis quelques semaines, mais j'ai quelques doutes sur l'allocation des blocs / warps / thread. J'étudie l'architecture d'un point de vue didactique (projet universitaire), donc atteindre des performances optimales n'est pas ma préoccupation.

Tout d'abord, j'aimerais comprendre si j'ai bien compris ces faits:

  1. Le programmeur écrit un noyau et organise son exécution dans une grille de blocs de threads.

  2. Chaque bloc est affecté à un multiprocesseur de streaming (SM). Une fois attribué, il ne peut pas migrer vers un autre SM.

  3. Chaque SM divise ses propres blocs en Warps (actuellement avec une taille maximale de 32 threads). Tous les threads d'un warp s'exécutent simultanément sur les ressources du SM.

  4. L'exécution réelle d'un thread est effectuée par les cœurs CUDA contenus dans le SM. Il n'y a pas de mappage spécifique entre les threads et les cœurs.

  5. Si une chaîne contient 20 threads, mais qu'il n'y a actuellement que 16 cœurs disponibles, la chaîne ne fonctionnera pas.

  6. Par contre si un bloc contient 48 threads, il sera divisé en 2 warps et ils s'exécuteront en parallèle à condition que suffisamment de mémoire soit disponible.

  7. Si un thread démarre sur un cœur, alors il est bloqué pour l'accès à la mémoire ou pour une longue opération en virgule flottante, son exécution peut reprendre sur un cœur différent.

Ont-ils raison?

Maintenant, j'ai une GeForce 560 Ti donc selon les spécifications, elle est équipée de 8 SM, contenant chacun 48 cœurs CUDA (384 cœurs au total).

Mon objectif est de m'assurer que chaque cœur de l'architecture exécute les MÊMES instructions. En supposant que mon code ne nécessitera pas plus de registres que ceux disponibles dans chaque SM, j'ai imaginé différentes approches:

  1. Je crée 8 blocs de 48 threads chacun, de sorte que chaque SM ait 1 bloc à exécuter. Dans ce cas, les 48 threads s'exécuteront-ils en parallèle dans le SM (en exploitant tous les 48 cœurs disponibles pour eux)?

  2. Y a-t-il une différence si je lance 64 blocs de 6 threads? (En supposant qu'ils seront mappés uniformément parmi les SM)

  3. Si je "submerge" le GPU dans un travail planifié (en créant 1024 blocs de 1024 threads chacun, par exemple), est-il raisonnable de supposer que tous les cœurs seront utilisés à un certain moment et effectueront les mêmes calculs (en supposant que les threads ne jamais caler)?

  4. Existe-t-il un moyen de vérifier ces situations à l'aide du profileur?

  5. Y a-t-il une référence pour ce truc? J'ai lu le guide de programmation CUDA et les chapitres consacrés à l'architecture matérielle dans "Programming Massively Parallel Processors" et "CUDA Application design and development"; mais je n'ai pas pu obtenir de réponse précise.


Je voudrais ajouter en commentaire ce qui est "CUDA core". "CUDA core" ou "Execution unit" est un entier ALU et FPU entièrement pipelined qui exécute une instruction d'instruction arithmétique par cycle d'horloge dans un thread cuda.
bruziuz

Réponses:


123

Deux des meilleures références sont

  1. Livre blanc sur l'architecture de calcul NVIDIA Fermi
  2. Avis sur GF104

Je vais essayer de répondre à chacune de vos questions.

Le programmeur divise le travail en threads, les threads en blocs de threads et les blocs de thread en grilles. Le distributeur de travail de calcul alloue des blocs de thread aux multiprocesseurs de streaming (SM). Une fois qu'un bloc de thread est distribué à un SM, les ressources pour le bloc de thread sont allouées (warps et mémoire partagée) et les threads sont divisés en groupes de 32 threads appelés warps. Une fois qu'une chaîne est allouée, elle est appelée une chaîne active. Les deux planificateurs de distorsion choisissent deux déformations actives par cycle et envoient des déformations aux unités d'exécution. Pour plus de détails sur les unités d'exécution et la répartition des instructions, voir 1 p.7-10 et 2 .

4 ' . Il existe un mappage entre laneid (index des threads dans une chaîne) et un noyau.

5 ' . Si une chaîne contient moins de 32 threads, elle sera dans la plupart des cas exécutée de la même manière que si elle avait 32 threads. Les warps peuvent avoir moins de 32 threads actifs pour plusieurs raisons: le nombre de threads par bloc n'est pas divisible par 32, le programme exécute un bloc divergent donc les threads qui n'ont pas emprunté le chemin actuel sont marqués comme inactifs, ou un thread du warp est sorti.

6 ' . Un bloc de thread sera divisé en WarpsPerBlock = (ThreadsPerBlock + WarpSize - 1) / WarpSize Il n'est pas nécessaire que les planificateurs de chaîne sélectionnent deux warps dans le même bloc de thread.

7 ' . Une unité d'exécution ne se bloquera pas sur une opération de mémoire. Si une ressource n'est pas disponible lorsqu'une instruction est prête à être envoyée, l'instruction sera à nouveau distribuée dans le futur lorsque la ressource sera disponible. Les warps peuvent caler au niveau des barrières, sur les opérations de mémoire, les opérations de texture, les dépendances de données, ... Un warp bloqué ne peut pas être sélectionné par le planificateur de warp. Sur Fermi, il est utile d'avoir au moins 2 warps éligibles par cycle afin que le planificateur de warp puisse émettre une instruction.

Voir la référence 2 pour les différences entre une GTX480 et une GTX560.

Si vous lisez le matériel de référence (quelques minutes), je pense que vous constaterez que votre objectif n'a pas de sens. Je vais essayer de répondre à vos points.

1 ' . Si vous lancez le noyau <<< 8, 48 >>> vous obtiendrez 8 blocs chacun avec 2 warps de 32 et 16 threads. Il n'y a aucune garantie que ces 8 blocs seront attribués à différents SM. Si 2 blocs sont alloués à un SM, alors il est possible que chaque programmateur de chaîne puisse sélectionner une chaîne et exécuter la chaîne. Vous n'utiliserez que 32 des 48 cœurs.

2 ' . Il y a une grande différence entre 8 blocs de 48 threads et 64 blocs de 6 threads. Supposons que votre noyau n'a pas de divergence et que chaque thread exécute 10 instructions.

  • 8 blocs avec 48 fils = 16 chaînes * 10 instructions = 160 instructions
  • 64 blocs avec 6 fils = 64 chaînes * 10 instructions = 640 instructions

Afin d'obtenir une efficacité optimale, la division du travail doit être en multiples de 32 threads. Le matériel ne fusionnera pas les threads de différentes déformations.

3 ' . Un GTX560 peut avoir 8 blocs SM * 8 = 64 blocs à la fois ou 8 SM * 48 warps = 512 warps si le noyau n'atteint pas le maximum de registres ou de mémoire partagée. A tout moment, une partie du travail sera active sur les SM. Chaque SM a plusieurs unités d'exécution (plus de cœurs CUDA). Les ressources utilisées à un moment donné dépendent des ordonnanceurs de distorsion et du mélange d'instructions de l'application. Si vous n'effectuez pas d'opérations TEX, les unités TEX seront inactives. Si vous n'effectuez pas d'opération spéciale en virgule flottante, les unités SUFU seront inactives.

4 ' . Parallel Nsight et le spectacle Visual Profiler

une. IPC exécuté

b. IPC émis

c. déformations actives par cycle actif

ré. Warps éligibles par cycle actif (Nsight uniquement)

e. raisons de décrochage de la chaîne (Nsight uniquement)

F. threads actifs par instruction exécutée

Le profileur n'affiche le pourcentage d'utilisation d'aucune des unités d'exécution. Pour GTX560 une estimation approximative serait IssuedIPC / MaxIPC. Pour MaxIPC, supposons que GF100 (GTX480) est 2 GF10x (GTX560) est 4 mais que la cible est 3 est une meilleure cible.


1
Merci pour votre réponse. J'ai lu les références, mais il y a certaines choses que je ne comprends pas dans votre réponse. Dans les questions suivantes, je suppose que nous utilisons une architecture de Fermi avec 48 cœurs (16 cœurs * 3 "groupes de base"): 1. Vous avez mentionné une correspondance entre les cœurs et laneid. De quel type de cartographie s'agit-il? 2. D'après les références, j'ai obtenu que chaque "groupe central" exécute au plus une demi-chaîne (16 threads) par cycle d'horloge. Donc en théorie si nous avons 48 threads dans le même bloc, ils seront organisés en 3 demi-warps et s'exécuteront en parallèle sur les 48 cœurs. Ai-je raison?
Daedalus

1
Les noyaux CUDA sont le nombre d'unités FP simple précision. Penser l'exécution en termes de cœurs CUDA n'est pas correct. Chaque chaîne a 32 fils. Ces threads seront envoyés à un groupe d'unités d'exécution (par exemple 16 cœurs cuda). Afin d'émettre les 48 cœurs dans une seule horloge, l'un des deux programmateurs de distorsion doit sélectionner une déformation qui répond à la demande d'une paire superscalaire et les deux instructions doivent être d'un type exécuté par des cœurs CUDA. De plus, l'autre programmateur de chaîne doit choisir une chaîne dont la prochaine instruction sera exécutée par les cœurs CUDA.
Greg Smith

1
Il n'est pas nécessaire que les warps soient dans le même bloc ou que les warps d'un bloc aient le même compteur de programme.
Greg Smith

2
Dans votre exemple, chaque planificateur sélectionne une chaîne et émet 1 instruction. Dans ce cas, seuls 2 groupes d'unités d'exécution seront utilisés. Afin d'utiliser plus d'unités d'exécution, 1 des planificateurs doit émettre une double émission. Comme indiqué dans les références, il existe plusieurs types d'unités d'exécution (pas seulement ce que l'on appelle les cœurs cuda) et il existe des règles d'appariement d'instructions (pas bien documentées) qui doivent être respectées pour que les ordonnanceurs émettent une double émission.
Greg Smith

1
@GregSmith Je cherche partout sur le Web pour savoir d'où viennent ces 8 blocs actifs par SM dans l'architecture Fermi. Ce n'est même pas mentionné dans le livre blanc de fermi. Avez-vous d'autres références à ce sujet?
Greg K.

8

"E. Si une chaîne contient 20 threads, mais qu'il n'y a actuellement que 16 cœurs disponibles, la chaîne ne fonctionnera pas."

est incorrect. Vous confondez les cœurs dans leur sens habituel (également utilisé dans les processeurs) - le nombre de "multiprocesseurs" dans un GPU, avec les cœurs dans le marketing nVIDIA ("notre carte a des milliers de cœurs CUDA").

Un warp lui-même ne peut être planifié que sur un seul cœur (= multiprocesseur) et peut exécuter jusqu'à 32 threads en même temps; il ne peut pas utiliser plus d'un seul cœur.

Le nombre «48 warps» est le nombre maximum de warps actifs (warps qui peuvent être choisis pour être programmés pour le travail dans le prochain cycle, à n'importe quel cycle donné) par multiprocesseur, sur les GPU nVIDIA avec Compute Capability 2.x; et ce nombre correspond à 1536 = 48 x 32 fils.

Réponse basée sur ce webinaire


@GregSmith: A modifié la réponse pour résoudre ce problème. C'est bien que vous ayez été patient avec ça, mais - ça fait cinq ans ...
einpoklum

monocœur (= multiprocesseur)? Je pense que la question suppose la terminologie single core = processeur et non multiprocesseur. Avec votre terminologie, votre réponse est correcte.
Adarsh
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.