]> AND Private Git Repository - these_gilles.git/blob - THESE/Chapters/chapter1b/chapter1b.tex~
Logo AND Algorithmique Numérique Distribuée

Private GIT Repository
relecture vlad de 0 a 70
[these_gilles.git] / THESE / Chapters / chapter1b / chapter1b.tex~
1 \section{Pourquoi ?}
2 S'il fallait en réduire les raisons à une seule, c'est vraisemblablement la concurrence commerciale et la croissance du marché des jeux vidéos qui a poussé les fabricants de cartes graphiques à une innovation permanente qui a donnée naissance aux GPUs. 
3 Le rendu graphique dans ce cadre est une opération exigeante en calcul mais intrinsèquement parallèle car chaque pixel est traité individuellement. L'amélioration des résolutions à aussi contribuer à faire évoluer la nature de ces besoins de \textit{parallèle} à \textit{massivement parallèle}, un écran actuel pouvant comporter plus de  2,5 millions de pixels. 
4
5 La technologie de fabrication étant identique à celle de CPUs, c'est donc au niveau de la répartitions des fonctionnalités que les GPUs se distinguent : là où un CPU comporte quelques c\oe urs de calcul et beaucoup de transistors dédiés à la réalisation de mémoire cache et de contrôle de flux, un GPU présente plusieurs unités comportant chacun une grande quantité de c\oe urs de calcul ne disposant que de très peu de mémoire cache et de rudimentaires capacités de contrôle, comme l'illustrent les schémas de la figure \ref{fig-gpucpu1}.
6
7 \begin{figure}[h]
8   \centering
9   \includegraphics[width=10cm]{Chapters/chapter1b/img/gpucpu1.png}
10   \caption{Comparaison des structures d'un c\oe ur de GPU et d'un c\oe ur de CPU (d'après \cite{CUDAPG}).}
11   \label{fig-gpucpu1}
12 \end{figure}
13
14 Cette spécialisation des circuit GPUs a permis d'en améliorer les performances brutes beaucoup plus rapidement que pour les CPUs, au fil des évolutions de la technologie. Il en est allé de même pour les débits mémoire théoriques. Les graphiques de la figure \ref{fig-gpucpu2} comparent les rythmes de ces évolutions pour les GPU Nvidia\textregistered et pour les CPU Intel\textregistered.  
15
16 Les problèmes recquérant les capacités de calcul spécifiques des GPU ne sont cependant pas limités aux questions de rendu graphique, aussi les scientifiques ont-ils très vite cherché à tirer parti de la puissance de calcul croissante des GPUs pour traiter d'autres types de problèmes, faisant sens à l'acronyme GPGPU.
17
18 \begin{figure}[h]
19   \centering
20   \subfigure[Nombre maximum théorique d'opérations en virgule flottante par seconde en fonction de l'année et de l'architecture.]{\includegraphics[height=5cm]{Chapters/chapter1b/img/gpucpu2a.png}}\quad
21   \subfigure[Bande passante théorique maximale des diverses architectures.]{\includegraphics[height=5cm]{Chapters/chapter1b/img/gpucpu2b.png}}
22   \caption{Comparaison des performances des GPUs Nvidia et des CPU Intel (d'après \cite{CUDAPG}).}
23   \label{fig-gpucpu2}
24 \end{figure}
25
26 Malgré des caractéristiques prometteuses, les GPGPUs n'ont pas immédiatement declenché une vague d'expérimentations scientifiques dans des domaines variés, l'essentiel des travaux étant liés à la construction et la visualisation des données issues de l'instrumentation d'imagerie médicale. 
27
28 C'est la parution de l'extension de langage CUDA qui a réellement démocratisé l'emploi des GPGPUs et favorisé l'émergence de travaux variés. CUDA est une extension de haut niveau du langage C permetant d'écrire facilement des fonctions s'exécutant en parallèle sur le GPU, que l'on appelle des \textit{kernels}. L'extension CUDA permet également de gérer de manière transparente les changements d'échelle du parallélisme d'une architecture à une autre ou tout simplement les dimensions de la grille de calcul. Ces possibiltés rendent l'accès facile à la programmation GPU.
29
30 \section{Comment ?} 
31 \subsection{Le matériel}
32 Pour bien tirer parti des capacités des GPUs, il est important d'en comprendre l'organisation matérielle. Nous limiterons cette présentation à l'architecture dite \textit{Fermi} à laquelle appartient le GPU C2070 qui a servi à l'essentiel de nos expérimentations et dont la constitution  est détaillée par les diagrammes de la figure \ref{fig-c2070}.
33
34 Le circuit se divise en 4 groupes de processeurs de flux (les SMs), chacun groupe en comprenant 3 ou 4 pour un total de 14 SMs.
35 Chaque SM héberge à son tour 32 c\oe urs de calcul (les SPs).
36 Les threads sont exécutés par paquets de 2$\times$16, soit 32 (les warps) sur les 32 c\oe urs de calcul. 
37
38 \begin{figure}[h]
39   \centering
40   \subfigure[Organisation en groupes de SMs ]{\includegraphics[height=5cm]{Chapters/chapter1b/img/fermi.png}}\quad
41   \subfigure[Constitution d'un SM.]{\includegraphics[height=5cm]{Chapters/chapter1b/img/fermi-sm.png}}
42   \caption{Organisation des GPU d'architecture Fermi, comme le C2070 (d'après www.hpcresearch.nl).}
43   \label{fig-c2070}
44 \end{figure}
45
46 Les ressources mémoire sont de plusieurs nature tant du point de vue volume disponible, que portée ou bien débit. Le tableau \ref{tab-gpu-memoire} en synthétise les caractéristiques. Il faut retenir que les registres sont peu nombreux, embarqués sur le circuit (on-chip) et présentent les meilleures performances alors que la mémoire principale, dite globale, est externe au circuit (off-chip), de grande capacité mais présente des latences importantes de plusieurs centaines de cycles d'horloge.
47
48 Une petite quantité de mémoire on-chip est présente sur chaque SM et permet la communication entre les threads s'exécutant sur ce SM. Cette mémoire est appelée \textit{mémoire partagée} et permet des débits bien supérieurs à la mémoire globale.
49
50 \begin{table}[h]
51   \centering
52 \begin{tabular}[htb]{lcccccc}
53       \toprule
54       &\multicolumn{4}{c}{Propriétés}\\
55               \cmidrule(r){2-6}
56               &Emplacement  &Portée&Latence &débit &Taille  \\
57               &(on/off-chip)&      &(cycles)&(Go/s)&(octets)\\
58               \cmidrule(r){2-6}
59           Registres&   on-chip   &thread&1         &8000& 32K par SM  \\
60           Partagée &   on-chip   &bloc  &38        &1300&  48K        \\
61           \midrule
62           Constante&   off-chip  &grille&370/46/140 &8000& 64K        \\
63           Texture  &   off-chip  &grille&500/260/372&\ldots & 6G         \\
64           Locale   &   off-chip  &thread&550        &\ldots    & 512K       \\
65           Globale  &   off-chip  &grille&580/80/350 &144 & 6G         \\
66       \bottomrule
67 \end{tabular}
68    \caption{Caractéristiques des différents types de mémoire disponibles sur le GPU. Pour les mémoires cachées, les latences sont données selon l'accès \textit{sans-cache/L1/L2/}. Les mesures ont été obtenues à l'aide des microprogrammes de test de \cite{wong2010demystifying}.}
69       \label{tab-gpu-memoire}
70 \end{table}
71
72 \subsection{Le logiciel}
73 Dans le modèle CUDA, chaque \textit{kernel} est exécuté par un certain nombre de threads. Chaque thread possède un identifiant unique, accessible à l'intérieur du kernel, ce qui permet d'en individualiser le traitement.
74 L'ensemble des threads est organisé en plusieurs blocs indépendants, puis ces blocs en grille. Pour faciliter la représentation de modéles variés, les blocs de threads ainsi que la grille de blocs peuvent être décrits par des tableaux à une, deux ou trois dimensions.
75 Le nombre total de threads appartenant à un même bloc est cependant limité, selon la version de GPU, à 512 ou 1024.
76
77 Au sein d'un même bloc, les threads peuvent communiquer efficacement grâce à la mémoire partagée, rapide et présentant une faible latence.
78 La communication inter-blocs passe nécessairement par la mémoire globale dont l'emploi est pénalisant. 
79
80 L'emploi de la mémoire partagée n'est cependant pas transparent comme peut l'être un cache de niveau 1 (L1) et les motifs d'accès doivent respecter un certain nombre de conditions pour en obtenir les performances attendues. Le non respect de ces contraintes conduit le plus souvent à un bout programme dont l'exécution s'avère plus lente que son équivalent CPU.
81
82 Pour atteindre les meilleures performances possible, le fabricant Nvidia recommande d'avoir toujours suffisamment de threads dans chaque bloc et de blocs dans la grile et ce, pour masquer les latences des accès aux mémoires, mais aussi celles des instructions arithmétiques.
83 Il définit un indice nommé \textit{occupancy}, que l'on  pourrait franciser par \textit{charge} qui représente, à chaque instant, le rapport du nombre de blocs de threads actifs par SM sur le nombre maximum de blocs actifs par SM (48 sur C2070). 
84
85 La valeur de l'\textit{occupancy} peut se trouver limitée par un usage trop intensif des ressources mémoire par les threads ou bien par une grille de calcul mal dimensionnée. L'ensemble des paramètres intervenant dans le calcul l'\textit{occupancy} est pris en compte dans une feuille de tableur (l'\textit{occupancy calculator}) fournie par Nvidia pour aider les développeurs à bien employer les ressources des divers modèles de GPU.  
86
87 Nous verrons toutefois que cette notion peut-être remise en question, et que la lecture du tableau \ref{tab-gpu-memoire} peut nous guider vers une autre façon d'obtenir des performances élevées sur GPU.   
88