Programmation GPU
Apprenez les principes de la programmation GPU avec des QCM : hiérarchie grid/block/warp, mémoire partagée, accès mémoire coalescés, divergence de warp et occupation.
Programmation GPU : points clés
Un GPU est un processeur qui excelle à exécuter simultanément des milliers à des dizaines de milliers de threads appliquant la même opération à de grandes quantités de données. Les programmes expriment le parallélisme selon une hiérarchie de grids, de blocks et de threads, et le matériel exécute en lockstep des groupes d'environ 32 threads appelés warps.
Obtenir des performances exige des accès mémoire coalescés, où des threads voisins lisent des adresses voisines, l'usage de la mémoire partagée sur puce au sein d'un block, l'absence de divergence dans un warp et une occupation suffisante pour masquer la latence mémoire. Ce thème se concentre sur des principes indépendants des générations de produits.
Toutes les questions sur Programmation GPU (50)
- Quelle est la différence de philosophie de conception entre CPU et GPU ?
- Quelle est la caractéristique la plus adaptée d'une tâche que le GPU traite rapidement ?
- Quel traitement tend à être peu efficace lorsqu'il est exécuté sur GPU ?
- Quelle est la définition du « noyau » (kernel) en programmation GPU, par exemple en CUDA ?
- Quelle est la hiérarchie correcte des threads en CUDA (du plus grand au plus petit) ?
- Dans un noyau CUDA, l'indice i de chaque thread est obtenu par l'expression ci-dessus. Que vaut i pour le thread tel que blockIdx.x=2, blockDim.x=256 et threadIdx.x=5 ?
- On veut traiter un tableau de 1000 éléments à raison d'un élément par thread, avec 256 threads par bloc. Combien de blocs faut-il lancer ?
- Pourquoi le noyau CUDA ci-dessus contient-il « if (i < n) » ?
- Comment appelle-t-on, sur les GPU NVIDIA, l'unité regroupant 32 threads qui exécutent simultanément la même instruction ?
- Quelle est la différence entre le mode SIMT (instruction unique, threads multiples) des GPU et les instructions SIMD des CPU ?
- Dans un warp, un branchement conditionnel envoie la moitié des threads dans la branche if et l'autre moitié dans la branche else (divergence de warp). Comment l'exécution se déroule-t-elle généralement ?
- Les codes (1) et (2) ci-dessus font tous deux exécuter A à la moitié des threads et B à l'autre moitié. Quelle explication est correcte du point de vue de l'efficacité des warps (32 threads par warp) ?
- Quelle est la définition de l'accès mémoire coalescé (coalescing) sur GPU ?
- Avec i l'indice de chaque thread, lire le tableau tous les 32 éléments comme ci-dessus est plus lent que lire a[i]. Quelle en est la raison principale ?
- Pour traiter sur GPU des données de particules ayant des positions x, y et z, quelle disposition est avantageuse du point de vue de l'accès mémoire coalescé ?
- Quelle est la caractéristique de la mémoire partagée (shared memory) en CUDA ?
- Quel est le rôle de __syncthreads() en CUDA ?
- En CUDA, __syncthreads() est placé dans « if (threadIdx.x < 16) », de sorte que seuls certains threads le franchissent. Que peut-il se produire ?
- Quelle est la définition des conflits de banc (bank conflicts) de la mémoire partagée CUDA ?
- Un tableau de 32×32 float est placé en mémoire partagée ; sa lecture par colonne (verticalement) par les 32 threads d'un warp provoque des conflits de banc. Quelle contre-mesure est couramment utilisée ?
- Lors du calcul d'un produit de grandes matrices sur GPU, pourquoi découpe-t-on les matrices en petites tuiles chargées en mémoire partagée ?
- Que peut-il se produire si un noyau GPU utilise trop de registres par thread ?
- Quelle est la définition de l'occupation (occupancy) d'un GPU ?
- Quelle est la principale méthode par laquelle le GPU masque la longue latence mémoire (plusieurs centaines de cycles) ?
- Quel énoncé est correct au sujet de l'occupation d'un GPU ?
- Quelle est la relation entre les blocs et les SM (multiprocesseurs de flux) en CUDA ?
- En CUDA, on veut, au milieu d'un noyau, attendre que tous les autres blocs aient terminé leur calcul avant de passer à l'étape suivante. Quelle est la méthode usuelle ?
- Pour construire sur GPU l'histogramme des valeurs de pixels, faire ajouter directement par tous les threads via atomicAdd dans les 256 cases en mémoire globale peut être lent. Quelle méthode l'améliore ?
- Pour calculer sur GPU la somme d'un grand nombre de valeurs, pourquoi utilise-t-on une réduction en arbre (répétition de l'addition de voisins qui divise par deux le nombre de valeurs) ?
- Combien d'étapes faut-il pour sommer 1024 valeurs par une réduction en arbre ?
- Dans un programme utilisant un GPU discret, quel énoncé est généralement correct au sujet de la mémoire côté CPU et côté GPU ?
- Envoyer des données au GPU pour un traitement léger, comme une seule addition par élément d'un tableau, peut être plus lent qu'un calcul sur CPU. Quelle en est la raison principale ?
- Pourquoi le transfert vers le GPU est-il plus rapide lorsque la mémoire CPU est épinglée (verrouillée en pages) ?
- Quel est l'objectif principal de l'utilisation de plusieurs flux (streams) CUDA ?
- Un programme qui lance des milliers de fois de suite des noyaux très petits est lent. Quelle amélioration est la plus appropriée ?
- Quelle est la définition de la mémoire unifiée (unified memory) de CUDA ?
- Lors de l'addition élément par élément de deux grands tableaux sur GPU (c[i] = a[i] + b[i]), qu'est-ce qui détermine principalement les performances ?
- Pourquoi, sur de nombreux GPU grand public pour le jeu, les performances en double précision (FP64) sont-elles bien inférieures (par exemple quelques dizaines de fois) à celles en simple précision (FP32) ?
- Quelle est la caractéristique des Tensor Cores (unités de calcul matriciel) des GPU récents ?
- En calcul en précision mixte sur GPU, pourquoi effectue-t-on souvent les multiplications en faible précision (FP16, etc.) et l'accumulation en FP32 ?
- La somme en virgule flottante des mêmes données calculée sur GPU diffère légèrement au dernier chiffre d'une exécution à l'autre. Quelle est la cause la plus probable ?
- Quelle règle générale guide le choix du nombre de threads par bloc en CUDA ?
- Quel est l'avantage d'écrire un noyau avec une boucle comme ci-dessus (boucle à pas de grille, grid-stride loop) ?
- Pour quel type d'accès la mémoire constante de CUDA est-elle particulièrement rapide ?
- Quelle est la caractéristique générale des caches GPU par rapport à ceux des CPU ?
- Quel est un exemple de mécanisme de programmation pour le calcul parallèle sur GPU et autres, utilisable aussi sur des GPU autres que NVIDIA ?
- Sur GPU, on veut extraire d'un tableau les seuls éléments satisfaisant une condition et les écrire de façon compacte dans un autre tableau (chaque thread produit 0 ou 1 sortie). Quel calcul parallèle est couramment utilisé pour déterminer l'adresse d'écriture de chaque thread ?
- Quelle hypothèse faut-il respecter lors de l'écriture d'un noyau GPU ?
- Lors de la transposition d'une grande matrice sur GPU (b[j][i] = a[i][j]), quel est l'objectif principal du passage par la mémoire partagée ?
- En CUDA, quel est généralement le comportement juste après le lancement d'un noyau par le programme côté CPU ?
Comparatifs sur ce thème
Autres thèmes de Systèmes informatiques
- Arithmétique des ordinateurs
- ISA et assembleur
- Compilateurs
- Éditeurs de liens, chargeurs et exécutables
- Système d'exploitation et matériel
- Hiérarchie mémoire
- Multicœur et synchronisation
- Pile matérielle et logicielle de l'IA
- Systèmes embarqués et firmware
- HDL et vérification
- Interfaces d'E/S et bus
- Analyse des performances
- Sécurité matérielle
- Gestion de l'énergie