Mais c'est quoi le rapport entre les cartes graphiques et le parallélisme ?

Et bien les cartes graphiques intègrent des processeurs spécialisés dont l'architecture est fortement parallèle. Ces derniers sont appelés des Graphic Processing Unit, abréviées GPU. Ces dernières années, ces GPU sont devenus de plus en plus programmables, et l'idée d'utiliser ceux-ci pour effectuer des calculs génériques s'est peu à peu répandue. De nos jours, nos GPU peuvent effectuer des taches qui auraient étè dévolues au processeur il y a quelques années. Des couches logicielles comme CUDA ou OpenMP permettent ainsi de paralléliser des programmes et en exécuter certaines portions sur ces GPU. Aussi, comprendre le fonctionnement de ces GPU devient un impératif pour faire du calcul à haute performances. Voyons un peu ce que nos GPU ont dans le ventre.

Vieux GPUs

Cela fait un moment que les cartes graphiques de nos ordinateurs sont devenues programmables. Sur les premières cartes graphiques programmables, on pouvait créer des Shaders, des petits programmes permettant de manipuler des pixels ou des données géométriques (des Vertex). Pour traiter ces Shaders, notre carte graphique incorporait des unités de traitement, capables d’exécuter des instructions sur des pixels ou des données géométriques. Ces unités de traitement n'étaient ni plus ni moins que de processeurs assez rudimentaires, capables d'effectuer des instructions entières et flottantes.

Image utilisateur

Et ces derniers n'étaient pas identiques : les instructions qu'ils étaient capables d'effectuer n'étaient pas les mêmes suivant que ces processeurs traitaient de la géométrie ou des pixels. Avec le temps, l'idée d'utiliser ces processeurs pour autre chose que des traitement graphique fit son chemin. Ces processeurs furent alors un peu modifiés.

Stream Processors

De nos jours, ces processeurs sont tous identiques et peuvent servir à faire aussi bien des calculs graphiques que des calculs sur des données quelconques. Ces processeurs sont ce qu'on appelle des Streams Processors, des processeurs spécialement conçus pour exécuter des suites d'instructions sur un grand nombre de données.

Sur ces processeurs, des programmes, nommés Kernels, sont appliqués entièrement à un tableau de donnée que l'on appelle un Stream. Dans nos cartes graphiques actuelles, ce Stream est découpé en morceaux qui seront chacun traités sur un Stream Processor. Chacun de ces morceaux est appelé un Thread. Vous remarquerez que le terme Thread est ici utilisé dans un sens différent de celui utilisé précédemment. Faites attention ! Quoiqu'il en soit, ces processeurs ressemblent fortement aux processeur vectoriels ou aux processeurs utilisant des instructions SIMD.

Un GPU actuel est souvent composé de plusieurs de ces Streams Processors, placés ensembles sur une même puce, avec quelques autres circuits annexes, utilisés dans les taches de rendu 3D. Ces Streams Processors sont alors pilotés par un gros micro-contrôleur qui se charge de découper le Stream à traiter en Threads, avant de les répartir sur les différents Streams Processors de la puce.

Image utilisateur

On remarque que le découpage du Stream en Threads se fait à l’exécution. C'est assez différent de ce qu'on trouve sur les processeurs SIMD ou vectoriels. Sur ces derniers, les instructions du processeur travaillent sur des données de taille fixe : pour traiter un tableau complet, on doit utiliser une boucle pour traiter celui-ci morceau par morceau. Rien de tout cela sur nos cartes 3D : on envoie à notre carte 3D des informations sur le tableau à manipuler et celle-ci se débrouille toute seule pour le découper en morceau et les répartir sur les processeurs disponibles.

L'ensemble est souvent complété par quelques petites mémoires, qui servent à stocker des constantes ou des textures de façon temporaire, et qui sont utilisables par tous les Streams Processors de la puce. On retrouve parfois plusieurs mémoires caches partagées entre les différents Streams Processors. C'est de plus en plus le cas sur les cartes graphiques actuelles.

L'auteur