OpenACC Tutorial - Adding directives/fr: Difference between revisions

Updating to match new version of source page
(Updating to match new version of source page)
(Updating to match new version of source page)
Line 4: Line 4:
|title=Objectifs d'apprentissage
|title=Objectifs d'apprentissage
|content=
|content=
<div class="mw-translate-fuzzy">
* comprendre le processus de transfert (''offloading'')
* comprendre le processus de transfert (''offloading'')
* comprendre ce qu'est une directive OpenACC  
* comprendre ce qu'est une directive OpenACC  
Line 10: Line 11:
* comprendre le concept d'alias en C/C++
* comprendre le concept d'alias en C/C++
* savoir utiliser la rétroaction du compilateur et éviter les faux alias
* savoir utiliser la rétroaction du compilateur et éviter les faux alias
</div>
}}
}}


<div class="mw-translate-fuzzy">
== Transfert vers un processeur graphique (GPU) ==  
== Transfert vers un processeur graphique (GPU) ==  
Avant de porter du code sur un GPU, il faut savoir qu'ils ne partagent pas la même mémoire que le processeur (CPU);  autrement dit, le GPU n'a pas un accès direct à la mémoire de départ. Cette dernière est en général plus grande, mais plus lente que la mémoire du GPU. Pour pouvoir utiliser un GPU, les données doivent passer par le bus PCI, dont la bande passante est moins grande que celles du CPU et du GPU. Il est donc de la plus haute importance de bien gérer les transferts entre la mémoire de départ et le GPU.  En anglais, ce processus s'appelle ''offloading''.
Avant de porter du code sur un GPU, il faut savoir qu'ils ne partagent pas la même mémoire que le processeur (CPU);  autrement dit, le GPU n'a pas un accès direct à la mémoire de départ. Cette dernière est en général plus grande, mais plus lente que la mémoire du GPU. Pour pouvoir utiliser un GPU, les données doivent passer par le bus PCI, dont la bande passante est moins grande que celles du CPU et du GPU. Il est donc de la plus haute importance de bien gérer les transferts entre la mémoire de départ et le GPU.  En anglais, ce processus s'appelle ''offloading''.
</div>


<div class="mw-translate-fuzzy">
==Directives OpenACC== <!--T:4-->
==Directives OpenACC== <!--T:4-->
Les directives OpenAcc sont semblables aux directives OpenMP. En C/C++, ce sont des <tt>pragmas</tt>  et en Fortran, des commentaires. L'emploi de directives comporte plusieurs avantages. Premièrement, puisque le code est peu affecté, les modifications peuvent se faire de manière incrémentale, un <tt>pragma</tt> à la fois;  ceci est particulièrement utile pour le débogage puisqu'il est ainsi facile d'identifier le changement précis qui crée le bogue. Deuxièmement, OpenACC peut être désactivé au moment de la compilation;  les <tt>pragmas</tt> sont alors vus comme étant des commentaires et ne sont pas considérés par le compilateur, ce qui permet de compiler une version accélérée et une version normale à partir du même code source. Troisièmement, comme le compilateur fait tout le travail de transfert, le même code peut être compilé pour différents types d'accélérateurs, que ce soit un GPU, un Xeon Phi (MIC) ou un CPU;    ainsi, un changement du matériel exigera simplement la mise à jour du compilateur, sans modification au code.  
Les directives OpenAcc sont semblables aux directives OpenMP. En C/C++, ce sont des <tt>pragmas</tt>  et en Fortran, des commentaires. L'emploi de directives comporte plusieurs avantages. Premièrement, puisque le code est peu affecté, les modifications peuvent se faire de manière incrémentale, un <tt>pragma</tt> à la fois;  ceci est particulièrement utile pour le débogage puisqu'il est ainsi facile d'identifier le changement précis qui crée le bogue. Deuxièmement, OpenACC peut être désactivé au moment de la compilation;  les <tt>pragmas</tt> sont alors vus comme étant des commentaires et ne sont pas considérés par le compilateur, ce qui permet de compiler une version accélérée et une version normale à partir du même code source. Troisièmement, comme le compilateur fait tout le travail de transfert, le même code peut être compilé pour différents types d'accélérateurs, que ce soit un GPU, un Xeon Phi (MIC) ou un CPU;    ainsi, un changement du matériel exigera simplement la mise à jour du compilateur, sans modification au code.
</div>


Le code de notre exemple contient deux boucles&nbsp;:  la première initialise deux vecteurs et la seconde effectue une opération de [https://fr.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms niveau 1] d'addition des vecteurs.  
<div class="mw-translate-fuzzy">
Le code de notre exemple contient deux boucles&nbsp;:  la première initialise deux vecteurs et la seconde effectue une opération de [https://fr.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms niveau 1] d'addition des vecteurs.
</div>


{| class="wikitable" width="100%"
{| class="wikitable" width="100%"
Line 49: Line 57:
</syntaxhighlight>
</syntaxhighlight>
|}
|}
<div class="mw-translate-fuzzy">
Dans les deux cas, le compilateur identifie deux noyaux (''kernels''). En C/C++, les deux noyaux sont à l'intérieur de chaque boucle.  En Fortran, les noyaux sont à l'intérieur de la première boucle et à l'intérieur de la boucle implicite effectuée lors d'une opération sur des tableaux.
Dans les deux cas, le compilateur identifie deux noyaux (''kernels''). En C/C++, les deux noyaux sont à l'intérieur de chaque boucle.  En Fortran, les noyaux sont à l'intérieur de la première boucle et à l'intérieur de la boucle implicite effectuée lors d'une opération sur des tableaux.
</div>


<div class="mw-translate-fuzzy">
Remarquez que le bloc OpenACC est délimité en C/C++ par des accolades; en Fortran, le commentaire est placé une fois au début et une dernière fois à la fin, avec l'ajout cette fois de <tt>end</tt>.
Remarquez que le bloc OpenACC est délimité en C/C++ par des accolades; en Fortran, le commentaire est placé une fois au début et une dernière fois à la fin, avec l'ajout cette fois de <tt>end</tt>.
</div>


<div class="mw-translate-fuzzy">
=== Loop et kernels ===
=== Loop et kernels ===
Quand le compilateur lit la directive OpenACC <tt>kernels</tt>, il analyse le code pour identifier les sections pouvant être parallélisées. Ceci correspond souvent au corps d'une boucle. Dans ce cas, le compilateur délimite le début et la fin du corps du code avec la fonction ''kernel''. Les appels à cette fonction ne seront pas affectés par les autres appels. La fonction est compilée et peut ensuite être exécutée sur un accélérateur. Comme chaque appel est indépendant, chacun des milliers de cœurs de l'accélérateur peut exécuter la fonction en parallèle pour un index spécifique.
Quand le compilateur lit la directive OpenACC <tt>kernels</tt>, il analyse le code pour identifier les sections pouvant être parallélisées. Ceci correspond souvent au corps d'une boucle. Dans ce cas, le compilateur délimite le début et la fin du corps du code avec la fonction ''kernel''. Les appels à cette fonction ne seront pas affectés par les autres appels. La fonction est compilée et peut ensuite être exécutée sur un accélérateur. Comme chaque appel est indépendant, chacun des milliers de cœurs de l'accélérateur peut exécuter la fonction en parallèle pour un index spécifique.
</div>
When the compiler reaches an OpenACC <tt>kernels</tt> directive, it will analyze the code in order to identify sections that can be parallelized.
This often corresponds to the body of a loop that has independent iterations.
When such a case is identified, the compiler will first wrap the body of the loop into a special function called a [https://en.wikipedia.org/wiki/Compute_kernel ''kernel''].
This internal code refactoring makes sure that each call to the kernel is independent from any other call.
The kernel is then compiled to enable it to run on an accelerator.
Since each call is independent, each one of the hundreds of cores of the accelerator can run the function for one specific index in parallel.
{| class="wikitable" width="100%"
{| class="wikitable" width="100%"
|-
<div class="mw-translate-fuzzy">
! LOOP !! KERNELS
LOOP
</div>
|-
|-
| <syntaxhighlight lang="cpp" line>
| <syntaxhighlight lang="cpp" line>
Line 65: Line 88:
}
}
</syntaxhighlight> || <syntaxhighlight lang="cpp" line>
</syntaxhighlight> || <syntaxhighlight lang="cpp" line>
void loopBody(A,B,C,i)
void kernelName(A, B, C, i)
{
{
   C[i] = A[i] + B[i];
   C[i] = A[i] + B[i];
}
}
</syntaxhighlight>
</syntaxhighlight>
|-
<div class="mw-translate-fuzzy">
|Calcule de 0-N, dans l'ordre || Chaque cœur de calcul traite une valeur de <tt>i</tt>.
Calcule de 0-N, dans l'ordre
</div>
|}
|}


Line 379: Line 403:
}}
}}


<div class="mw-translate-fuzzy">
[https://docs.computecanada.ca/wiki/OpenACC_Tutorial_-_Data_movement/fr Page suivante, Mouvement des données]<br>
[https://docs.computecanada.ca/wiki/OpenACC_Tutorial_-_Data_movement/fr Page suivante, Mouvement des données]<br>
[https://docs.computecanada.ca/wiki/OpenACC_Tutorial/fr Retour au début du tutoriel]
[https://docs.computecanada.ca/wiki/OpenACC_Tutorial/fr Retour au début du tutoriel]
</div>
38,760

edits