Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
formation:etsn2022gpu [2022/07/20 16:53]
equemene [Intégration et exploitation du code Gromacs]
formation:etsn2022gpu [2022/08/12 11:35] (Version actuelle)
equemene [Prérequis en matériel, logiciel et humain]
Ligne 1: Ligne 1:
 ====== ETSN 2022 : les GPU, la technologie disruptive du 21ème siècle ====== ====== ETSN 2022 : les GPU, la technologie disruptive du 21ème siècle ======
  
-<note warning>En construction</​note>​+<note warning>Contient certainement encore un nombre non négligeable de coquilles... Merci de votre compréhension. Mon adresse de courriel est en bas pour vous permettre d'en assurer l'​amélioration !</​note>​
  
-Cette cession ​de travaux pratiques se compose de 7 séances de 1h30 du workshop [[https://​conferences.cirm-math.fr/​2842.html|Les GPU, technologie disruptive du 21ème siècle]]. Elle s'​accompagne de 5 cours donnés par Emmanuel Quémener.+Cette session ​de travaux pratiques se compose de 7 séances de 1h30 du workshop [[https://​conferences.cirm-math.fr/​2842.html|Les GPU, technologie disruptive du 21ème siècle]]. Elle s'​accompagne de 5 cours suivants ​donnés par Emmanuel Quémener. 
 + 
 +    * Cours 1 & 2 : [[http://​www.cbp.ens-lyon.fr/​emmanuel.quemener/​documents/​ETSN_IntroductionGPU_Cours12.pdf|Les GPU : technologie disruptive du 21e siècle]] 
 +    * Cours 3 : [[http://​www.cbp.ens-lyon.fr/​emmanuel.quemener/​documents/​ETSN_PortageEtMetrologie_Cours3.pdf|Portage d'un vieux code, l'​occasion d'un retour sur 40 ans d'​informatique]] 
 +    * Cours 4 : [[http://​www.cbp.ens-lyon.fr/​emmanuel.quemener/​documents/​ETSN_MetrologieGPU_Cours4.pdf|Métrologie d'​applications]] 
 +    * Cours 5 : [[http://​www.cbp.ens-lyon.fr/​emmanuel.quemener/​documents/​ETSN_CodesMatrices_Cours5.pdf|Emergence de Codes "​Matrices"​ et conclusion]]
  
 ===== CQQCOQP : Comment ? Qui ? Quand ? Combien ? Où ? Quoi ? Pourquoi ? ===== ===== CQQCOQP : Comment ? Qui ? Quand ? Combien ? Où ? Quoi ? Pourquoi ? =====
Ligne 21: Ligne 26:
 ===== Déroulement des sessions pratiques ===== ===== Déroulement des sessions pratiques =====
  
-Le programme est volontairement touffu mais les explications données et les corrigés devraient permettre de poursuivre l'​apprentissage par la pratique hors de cette école d'​une ​seule semaine.+Le programme est volontairement touffu mais les explications données et les corrigés devraient permettre de poursuivre l'​apprentissage par la pratique hors de cette école d'​une ​unique ​semaine.
  
   * Prise en main de l’environnement à distance du [[https://​www.cbp.ens-lyon.fr/​doku.php|Centre Blaise Pascal]] à l'​[[https://​www.ens-lyon.fr|ENS-Lyon]]   * Prise en main de l’environnement à distance du [[https://​www.cbp.ens-lyon.fr/​doku.php|Centre Blaise Pascal]] à l'​[[https://​www.ens-lyon.fr|ENS-Lyon]]
Ligne 28: Ligne 33:
   * Un intermède Python/CUDA pour tester //​l'​autre//​ implémentation sur GPU   * Un intermède Python/CUDA pour tester //​l'​autre//​ implémentation sur GPU
   * La réalisation et le portage d'une transformée de Fourier discrète   * La réalisation et le portage d'une transformée de Fourier discrète
-  * Choix du périphérique en Python, avec exploration d'​autres programmes +  * Choix du périphérique en Python ​et sa programmation 
-  * Utilisation des librairies externesexemple avec xGEMM+  * Utilisation des librairies externes ​exemple avec xGEMM
   * Intégration de "codes métier"​ : [[https://​www.tensorflow.org/​|TensorFlow]],​ [[https://​www.r-ccs.riken.jp/​labs/​cbrt/​|GENESIS]] et [[http://​www.gromacs.org/​|Gromacs]]   * Intégration de "codes métier"​ : [[https://​www.tensorflow.org/​|TensorFlow]],​ [[https://​www.r-ccs.riken.jp/​labs/​cbrt/​|GENESIS]] et [[http://​www.gromacs.org/​|Gromacs]]
 +  * Expoitation de codes //​Matrices//​ pour la métrologie ​
 +
 +De manière à disposer d'une trace de votre travail et de pouvoir l'​évaluer,​ il est recommandé de rédiger un "livre de bord" sur la base des questions posées. N'​hésitez pas à faire des copies d'​écran et à les intégrer dans votre document. ​
  
-De manière à disposer d'une trace de votre travail et de pouvoir l'​évaluer,​ il est recommandé de rédiger un "livre de bord" sur la base des questions posées. N'​hésitez pas à faire des copies d'​écran et à les intégrer dans votre rapport. ​ 
 ===== Démarrage de la session ===== ===== Démarrage de la session =====
    
Ligne 41: Ligne 48:
 === Prérequis pour le matériel === === Prérequis pour le matériel ===
    
-  * Si vous n'​utilisez PAS le CBP, une machine relativement récente avec un GPU intégré ​avec circuit Nvidia+  * Si vous n'​utilisez PAS le CBP, une machine relativement récente avec une GPU intégrée ​avec circuit Nvidia
   * Si vous utilisez le CBP, un laptop disposant d'un écran assez confortable pour afficher une fenêtre de 1024x768, une connexion réseau la plus stable possible et la capacité d'y installer un logiciel adapté.   * Si vous utilisez le CBP, un laptop disposant d'un écran assez confortable pour afficher une fenêtre de 1024x768, une connexion réseau la plus stable possible et la capacité d'y installer un logiciel adapté.
  
 === Prérequis pour le logiciel === === Prérequis pour le logiciel ===
  
-  * Si vous n'​utilisez pas le CBP, un OS GNU/Linux correctement configuré pour le GPU embarqué ​avec tous les composants Nvidia, OpenCL, PyOpenCL, PyCUDA. A cela s'​ajoute un navigateur pour voir cette page ainsi qu'un traitement de texte pour rédiger le compte-rendu de ces séances.+  * Si vous n'​utilisez pas le CBP, un OS GNU/Linux correctement configuré pour la GPU embarquée ​avec tous les composants Nvidia, OpenCL, PyOpenCL, PyCUDA
 +    * Un ''​apt install time pciutils clinfo nvidia-opencl-icd nvidia-smi pocl-opencl-icd python3-pyopencl python-pyopencl-doc python-pycuda-doc python3-pycuda''​ devrait être suffisant comme prérequis pour une machine avec un circuit Nvidia pas trop ancien 
 +    * Pour les implémentations OpenCL sur CPU sur Debian ou Ubuntu, essayez d'​installer celle d'​[[http://​www.cbp.ens-lyon.fr/​emmanuel.quemener/​software/​opencl-1.2-intel-cpu_6.4.0.25-2_amd64.deb|Intel]] et celle d'​[[http://​www.cbp.ens-lyon.fr/​emmanuel.quemener/​software/​amd-opencl-icd_15.12-2~bpo8+3_fixed.deb|AMD]]. A votre environnement ​s'​ajoute un navigateur pour voir cette page ainsi qu'un traitement de texte pour rédiger le compte-rendu de ces séances. ​
   * Si vous utilisez le CBP, il faut avoir installé le logiciel [[https://​wiki.x2go.org/​doku.php/​download:​start|x2goclient]] suivant les recommandations de la [[ressources:​x2go4cbp|documentation du CBP]]. Il est recommandé d'​exploiter le traitement de texte et le navigateur dans la session distante.   * Si vous utilisez le CBP, il faut avoir installé le logiciel [[https://​wiki.x2go.org/​doku.php/​download:​start|x2goclient]] suivant les recommandations de la [[ressources:​x2go4cbp|documentation du CBP]]. Il est recommandé d'​exploiter le traitement de texte et le navigateur dans la session distante.
  
-Pour choisir "​judicieusement"​ une machine parmi la (presque) centaine ​de machines à disposition,​ consultez la page [[https://​www.cbp.ens-lyon.fr/​python/​forms/​CloudCBP|Cloud@CBP]]. Il est recommandé de prendre une machine disposant d'un GPU de type "​Gamer"​ ou d'un "​GPGPU"​. Les sélecteurs de la page précédente peuvent vous aider dans ce choix. Coordonnez vous entre vous pour être si possible chacun sur la vôtre. Ensuite, une fois connecté via x2go, il peut être intéressant de se connecter sur une autre machine de configuration différente pour comparer les résultats de vos expérimentations.+Pour choisir "​judicieusement"​ une machine parmi les plus de 130 de machines à disposition,​ consultez la page [[https://​www.cbp.ens-lyon.fr/​python/​forms/​CloudCBP|Cloud@CBP]]. Il est recommandé de prendre une machine disposant d'une GPU de type "​Gamer"​ ou d'une "​GPGPU"​. Les sélecteurs de la page précédente peuvent vous aider dans ce choix. Coordonnez-vous entre vous pour être si possible chacun sur la vôtre. Ensuite, une fois connecté via x2go, il peut être intéressant de se connecter sur une autre machine de configuration différente pour comparer les résultats de vos expérimentations.
  
 <note warning>​Etant donné la combinatoire des machines, leurs matériels respectifs et la galaxie des OS GNU/Linux et leurs versions, cela peut prendre de quelques minutes à plusieurs heures (voire jamais) de s'​assurer de la compatibilité de sa machine avec le prérequis logiciel. Donc l'​exploitation de l'​environnement du CBP, exactement construit pour suivre ces travaux pratiques, est TRES FORTEMENT recommandée.</​note>​ <note warning>​Etant donné la combinatoire des machines, leurs matériels respectifs et la galaxie des OS GNU/Linux et leurs versions, cela peut prendre de quelques minutes à plusieurs heures (voire jamais) de s'​assurer de la compatibilité de sa machine avec le prérequis logiciel. Donc l'​exploitation de l'​environnement du CBP, exactement construit pour suivre ces travaux pratiques, est TRES FORTEMENT recommandée.</​note>​
Ligne 67: Ligne 76:
   * Input and Output Devices : Périphériques d'​Entrée et Sortie   * Input and Output Devices : Périphériques d'​Entrée et Sortie
  
-Les GPU sont généralement considérés comme des périphériques d'​Entrée/​Sortie. Comme la plupart des périphériques installés dans les machines, ​ils exploitent un bus d'​interconnexion [[https://​en.wikipedia.org/​wiki/​Conventional_PCI|PCI]] ou [[https://​en.wikipedia.org/​wiki/​PCI_Express|PCI Express]].+Les GPU sont généralement considérés comme des périphériques d'​Entrée/​Sortie. Comme la plupart des périphériques installés dans les machines, ​elles exploitent un bus d'​interconnexion [[https://​en.wikipedia.org/​wiki/​Conventional_PCI|PCI]] ou [[https://​en.wikipedia.org/​wiki/​PCI_Express|PCI Express]].
  
 Pour récupérer la liste des périphériques PCI, utilisez la commande ''​lspci -nn''​. A l'​intérieur d'une longue liste apparaissent quelques périphériques **VGA** ou **3D**. Ce sont les périphériques GPU ou GPGPU. Pour récupérer la liste des périphériques PCI, utilisez la commande ''​lspci -nn''​. A l'​intérieur d'une longue liste apparaissent quelques périphériques **VGA** ou **3D**. Ce sont les périphériques GPU ou GPGPU.
Ligne 89: Ligne 98:
 </​note>​ </​note>​
  
-La totalité des stations de travail contiennent des cartes Nvidia.+La (presque) ​totalité des stations de travail contiennent des cartes Nvidia.
  
 Dans les systèmes **Posix** (**Unix** dans le langage courant), tout est fichier. Les informations sur les circuits Nvidia et leur découverte par le système d'​exploitation peuvent être récupérées avec un ''​grep''​ dans la commande ''​dmesg''​. Dans les systèmes **Posix** (**Unix** dans le langage courant), tout est fichier. Les informations sur les circuits Nvidia et leur découverte par le système d'​exploitation peuvent être récupérées avec un ''​grep''​ dans la commande ''​dmesg''​.
Ligne 170: Ligne 179:
 </​note>​ </​note>​
  
-Nvidia présente des informations sur l'​usage instantané de ses circuits avec la commande ''​nvidia-smi''​. Cette commande peut aussi être exploitée pour régler certains paramètres ​du GPU.+Nvidia présente des informations sur l'​usage instantané de ses circuits avec la commande ''​nvidia-smi''​. Cette commande peut aussi être exploitée pour régler certains paramètres ​de la GPU.
  
 Voici un exemple de sortie de la commande ''​nvidia-smi''​ : Voici un exemple de sortie de la commande ''​nvidia-smi''​ :
Ligne 202: Ligne 211:
   * ses puissances : instantanée et maximale   * ses puissances : instantanée et maximale
   * ses "​occupations"​ mémoire : instantanée et maximale   * ses "​occupations"​ mémoire : instantanée et maximale
-  * les processus les exploitant, leur consommation de mémoire et le GPU associé+  * les processus les exploitant, leur consommation de mémoire et la GPU associée
  
 <note warning> <note warning>
Ligne 211: Ligne 220:
 </​note>​ </​note>​
  
-Comme nous l'​avons vu dans l'​introduction sur le GPU, leur programmation peut-être réalisée par différentes voies. La première, pour les périphériques Nvidia, est d'​utiliser l'​environnement CUDA. Le problème sera qu'il est impossible de réexploiter votre programme sur une autre plate-forme (un CPU) ou la comparer avec d'​autres GPU. [[https://​www.khronos.org/​opencl/​|OpenCL]] reste une approche beaucoup plus polyvalente !+Comme nous l'​avons vu dans l'​introduction sur la GPU, leur programmation peut-être réalisée par différentes voies. La première, pour les périphériques Nvidia, est d'​utiliser l'​environnement CUDA. Le problème sera qu'il est impossible de réexploiter votre programme sur une autre plate-forme (une CPU) ou la comparer avec d'​autres GPU. [[https://​www.khronos.org/​opencl/​|OpenCL]] reste une approche beaucoup plus polyvalente !
  
 Sur les stations du CBP, la majorité des implémentations de OpenCL sont disponibles,​ autant sur CPU que sur GPU. Sur les stations du CBP, la majorité des implémentations de OpenCL sont disponibles,​ autant sur CPU que sur GPU.
Ligne 305: Ligne 314:
 </​note>​ </​note>​
  
-Il est aussi possible de choisir ​quel GPU Nvidia exploiter avec la variable d'​environnement ''​CUDA_VISIBLE_DEVICES''​. Il existe deux manières de l'​exploiter :+Il est aussi possible de choisir ​quelle ​GPU Nvidia exploiter avec la variable d'​environnement ''​CUDA_VISIBLE_DEVICES''​. Il existe deux manières de l'​exploiter :
   * en préfixant la commande à exécuter (ou son programme) par ''​CUDA_VISIBLE_DEVICES=#​GPU''​   * en préfixant la commande à exécuter (ou son programme) par ''​CUDA_VISIBLE_DEVICES=#​GPU''​
   * en //​exportant//​ la variable de manière permanente avec : ''​export CUDA_VISIBLE_DEVICES=#​GPU''​   * en //​exportant//​ la variable de manière permanente avec : ''​export CUDA_VISIBLE_DEVICES=#​GPU''​
Ligne 311: Ligne 320:
 La commande ''​nvidia-smi''​ offrait une liste de périphériques Nvidia identifiés mais les ''​ID''​ donnés sont dans l'​ordre inverse de celui exigé par ''​CUDA_VISIBLE_DEVICES''​. Par exemple, ''​nvidia-smi''​ donne comme ''​ID''​ les nombres ''​0''​ et ''​1''​. ​ La commande ''​nvidia-smi''​ offrait une liste de périphériques Nvidia identifiés mais les ''​ID''​ donnés sont dans l'​ordre inverse de celui exigé par ''​CUDA_VISIBLE_DEVICES''​. Par exemple, ''​nvidia-smi''​ donne comme ''​ID''​ les nombres ''​0''​ et ''​1''​. ​
 <​code>​ <​code>​
-# N'​exploiter que le GPU identifie #0 avec nvidia-smi+# N'​exploiter que la GPU identifie #0 avec nvidia-smi
 CUDA_VISIBLE_DEVICES=1 <​MonProgramme>​ CUDA_VISIBLE_DEVICES=1 <​MonProgramme>​
-# N'​exploiter que le GPU identifie #1 avec nvidia-smi+# N'​exploiter que la GPU identifie #1 avec nvidia-smi
 CUDA_VISIBLE_DEVICES=0 <​MonProgramme>​ CUDA_VISIBLE_DEVICES=0 <​MonProgramme>​
 # Exploiter les GPUs identifies #0 et #1 avec nvidia-smi # Exploiter les GPUs identifies #0 et #1 avec nvidia-smi
 CUDA_VISIBLE_DEVICES=0,​1 <​MonProgramme>​ CUDA_VISIBLE_DEVICES=0,​1 <​MonProgramme>​
-# N'​exploiter ​aucun GPU+# N'​exploiter ​aucune ​GPU
 CUDA_VISIBLE_DEVICES=''​ <​MonProgramme>​ CUDA_VISIBLE_DEVICES=''​ <​MonProgramme>​
 </​code>​ </​code>​
Ligne 349: Ligne 358:
 La (presque) totalité des outils exploités par le CBP pour comparer les CPU et les GPU se trouve dans le projet [[https://​forge.cbp.ens-lyon.fr/​redmine/​projects/​bench4gpu|bench4gpu]] du Centre Blaise Pascal. La (presque) totalité des outils exploités par le CBP pour comparer les CPU et les GPU se trouve dans le projet [[https://​forge.cbp.ens-lyon.fr/​redmine/​projects/​bench4gpu|bench4gpu]] du Centre Blaise Pascal.
  
-La récupération des sources est libre et se réalise par l'​outil subversion :<​code>​+La récupération des sources est libre et se réalise par l'​outil ​**subversion** (//NDLR : oui, je sais tout le monde est passé à GIT mais ce projet a plus de 10 ans//​) ​:<​code>​
 svn checkout https://​forge.cbp.ens-lyon.fr/​svn/​bench4gpu/​ svn checkout https://​forge.cbp.ens-lyon.fr/​svn/​bench4gpu/​
 </​code>​ </​code>​
Ligne 362: Ligne 371:
   * ''​Splutter''​ : un modèle de ''​postillonneur mémoire'',​ très utile pour évaluer les //fonctions atomiques//   * ''​Splutter''​ : un modèle de ''​postillonneur mémoire'',​ très utile pour évaluer les //fonctions atomiques//
   * ''​TrouNoir''​ : un exemple de portage de code de 1994, porté en C en 1997 puis en Python/​OpenCL et Python/CUDA en 2019   * ''​TrouNoir''​ : un exemple de portage de code de 1994, porté en C en 1997 puis en Python/​OpenCL et Python/CUDA en 2019
-  * ''​ETSN''​ : les éléments ​associés à cette école ETSN 2022+  * ''​ETSN''​ : les programmes //​corrigés// ​associés à cette école ETSN 2022
  
-De tous ces programmes, seuls ceux présents dans ''​BLAS'',​ ''​NBody'',​ ''​Pi''​ et ''​ETSN''​ seront exploités dans le cadre de ces travaux pratiques.+De tous ces programmes, seuls ceux présents dans ''​BLAS'',​ ''​NBody'',​ ''​Pi''​ et ''​ETSN''​ seront exploités dans le cadre de ces travaux pratiques. Il est quand même conseillé de ne pas se précipiter sur les corrigés situés dans ETSN pour le déroulement de ces séances. Le //no pain, no gain// s'​applique //aussi// dans l'​apprentissage en informatique.
  
 ===== Première exploration de l'​association Python et OpenCL ===== ===== Première exploration de l'​association Python et OpenCL =====
Ligne 408: Ligne 417:
 </​code>​ </​code>​
  
-Un programme aussi simple, que nous allons peu à peu modifier, va nous servir de socle pour explorer de nombreuses facettes de Python en général et les facettes de l'​exploitation des GPU en particulier.+Un programme aussi simple, que nous allons peu à peu modifier, va nous servir de socle pour explorer de nombreuses facettes de Python en général et l'​exploitation des GPU en particulier.
  
 En cas de succès à l'​exécution,​ sur une machine du CBP, par exemple la machine **gtxtitan**,​ le programme demande d'​abord de choisir une plateforme :<​code>​Choose platform: En cas de succès à l'​exécution,​ sur une machine du CBP, par exemple la machine **gtxtitan**,​ le programme demande d'​abord de choisir une plateforme :<​code>​Choose platform:
Ligne 466: Ligne 475:
  
 <note warning>​**Exercice #2.2 : modifier sans changer la sortie** <note warning>​**Exercice #2.2 : modifier sans changer la sortie**
- 
   - Modifiez ''​MySteps_0.py''​ suivant les 6 spécifications ci-dessus   - Modifiez ''​MySteps_0.py''​ suivant les 6 spécifications ci-dessus
   - Exécutez le programme pour plusieurs périphériques   - Exécutez le programme pour plusieurs périphériques
Ligne 482: Ligne 490:
   - une estimation de la vitesse d'​exécution en OpenCL pour différentes tailles   - une estimation de la vitesse d'​exécution en OpenCL pour différentes tailles
   - un ratio de performances entre mode natif et mode OpenCL   - un ratio de performances entre mode natif et mode OpenCL
 +  - la libération des mémoires réservées dans le bloc ''​OpenCLAddition''​
  
 Deux exécutions consécutives sur GPU et CPU permettront ainsi de visualiser le gain entre une exécution sur CPU et GPU. Deux exécutions consécutives sur GPU et CPU permettront ainsi de visualiser le gain entre une exécution sur CPU et GPU.
Ligne 488: Ligne 497:
  
 Le temps d'​exécution se basera sur un mécanisme très simple : l'​exploitation de 2 //timers//, le premier avant l'​exécution,​ le second après l'​exécution. Ce //timer// est la fonction ''​time()''​ de la librairie standard ''​time''​. ​ Le temps d'​exécution se basera sur un mécanisme très simple : l'​exploitation de 2 //timers//, le premier avant l'​exécution,​ le second après l'​exécution. Ce //timer// est la fonction ''​time()''​ de la librairie standard ''​time''​. ​
 +
 +Pour libérer l'​espace réservé sur le périphérique avec les opérations ''​Buffer'',​ il suffit d'​appeler la fonction ''​.release()''​ en suffixe de la variable. ​
  
 Par exemple, à la commande ''​PYOPENCL_CTX=0:​0 ./​MySteps_1.py 1048576'',​ l'​exécution répond :<​code> ​ Par exemple, à la commande ''​PYOPENCL_CTX=0:​0 ./​MySteps_1.py 1048576'',​ l'​exécution répond :<​code> ​
Ligne 507: Ligne 518:
  
 <note warning>​**Exercice #2.3 : instrumentation minimale du code** <note warning>​**Exercice #2.3 : instrumentation minimale du code**
- +  ​- Modifiez ''​MySteps_1.py''​ suivant les spécifications ci-dessus 
-  ​- Modifiez ''​MySteps_1.py''​ suivant les spécifications ci-dessus +  - Exécutez le programme pour des tailles de vecteurs de **2^15** à **2^30** 
-  - Exécutez le programme pour des tailles de vecteurs de **32768** à **1073741824** +    - sur la GPU la plus //performante//
-    - sur le GPU le plus //performant//+
     - sur l'​implémentation CPU la plus //​efficace//​ : l'​Intel     - sur l'​implémentation CPU la plus //​efficace//​ : l'​Intel
   - Analysez dans quelles situations des problèmes de produisent :   - Analysez dans quelles situations des problèmes de produisent :
Ligne 520: Ligne 530:
 Par exemple, sur la machine **gtxtitan** (déjà un peu ancienne), nous avons le tableau de résultats suivant : Par exemple, sur la machine **gtxtitan** (déjà un peu ancienne), nous avons le tableau de résultats suivant :
  
-Pour le GPU le plus performant, la GTX Titan avec 6GB de RAM :+Pour la GPU la plus performante, la GTX Titan avec 6GB de RAM :
 ^  Size  ^  NativeRate ​ ^  OpenCLRate ​ ^  Ratio  ^ ^  Size  ^  NativeRate ​ ^  OpenCLRate ​ ^  Ratio  ^
 ^  32768| ​ 892460736| ​ 25740| ​ 0.000029|  ​ ^  32768| ​ 892460736| ​ 25740| ​ 0.000029|  ​
Ligne 539: Ligne 549:
 ^  1073741824| ​ 644699087| ^  1073741824| ​ 644699087|
  
-Les cases //vides// ne sont pas des oublis : pour ces exécutions sur **gtxtitan**,​ le programme a planté. Dans notre cas, le message suivant s'​affichait<​code>​+Les cases //vides// ne sont pas des oublis : pour ces exécutions sur **gtxtitan**,​ le programme a //planté//. Dans notre cas, le message suivant s'​affichait<​code>​
 Traceback (most recent call last): Traceback (most recent call last):
   File "/​home/​equemene/​bench4gpu/​ETSN/​./​MySteps_1.py",​ line 71, in <​module>​   File "/​home/​equemene/​bench4gpu/​ETSN/​./​MySteps_1.py",​ line 71, in <​module>​
Ligne 551: Ligne 561:
 </​code>​ </​code>​
  
-Son origine était assez explicite avec le **MEM_OBJECT_ALLOCATION_FAILURE** renseignant sur un problème mémoire ou plus précisément sur un dépassement de capacité d'​allocation mémoire sur le périphérique.+Son origine était assez explicite avec le **MEM_OBJECT_ALLOCATION_FAILURE** renseignant sur un problème mémoire ou plus précisément sur un dépassement de capacité d'​allocation mémoire sur le périphérique. ​Dans cet exemple, la GPU sélectionnée est une **GTX Titan** avec 6GB de RAM. Notre programme planet dès que la taille des vecteurs dépasse 2^29 éléments soit 536870912. Si nous définissons 3 vecteurs composés de 536870912 flottants sur 32 bits, cela représente tout juste 6 GiB mais la GPU ne dispose que d'​exactement 6083 MiB. Il en manque à peine, mais il en manque suffisamment !
  
-Pour le CPU en implémentation Intel :+Pour la CPU en implémentation Intel :
 ^  Size  ^  NativeRate ​ ^  OpenCLRate ​ ^  Ratio  ^ ^  Size  ^  NativeRate ​ ^  OpenCLRate ​ ^  Ratio  ^
 ^  32768| ​ 803736570| ​ 48080| ​ 0.000060|  ​ ^  32768| ​ 803736570| ​ 48080| ​ 0.000060|  ​
Ligne 578: Ligne 588:
 Toutefois, intéressante consolation,​ nous notons que, lorsque nous augmentons la taille de nos vecteurs, la performance ne cesse d'​augmenter pour les implémentations OpenCL :  Toutefois, intéressante consolation,​ nous notons que, lorsque nous augmentons la taille de nos vecteurs, la performance ne cesse d'​augmenter pour les implémentations OpenCL : 
  
-<note important>​Utilier ​OpenCL, autant sur CPU que sur GPU, exige :+<note important>​Utiliser ​OpenCL, autant sur CPU que sur GPU, exige :
 un **nombre d'​éléments** sur lesquels s'​exécutent les opérations élémentaires est **conséquent** en fonction du périphérique de calcul (de plusieurs milliers à plusieurs millions) ; un **nombre d'​opérations élémentaires** à effectuer pour chaque élément d'une **densité arithmétique "​suffisante"​** (supérieures à la dizaine).</​note>​ un **nombre d'​éléments** sur lesquels s'​exécutent les opérations élémentaires est **conséquent** en fonction du périphérique de calcul (de plusieurs milliers à plusieurs millions) ; un **nombre d'​opérations élémentaires** à effectuer pour chaque élément d'une **densité arithmétique "​suffisante"​** (supérieures à la dizaine).</​note>​
  
Ligne 585: Ligne 595:
 Partons donc de notre programme précédent ''​MySteps_1.py''​ et copions le dans le programme ''​MySteps_2.py''​. Partons donc de notre programme précédent ''​MySteps_1.py''​ et copions le dans le programme ''​MySteps_2.py''​.
  
-Nous allons intégrer dans ce programme la fonction empilant successivement les 16 opérations : ''​cos'',''​arccos'',''​sin'',''​arcsin'',''​tan'',''​arctan'',''​cosh'',''​arccosh'',''​sinh'',''​arcsinh'',''​tanh'',''​arctanh'',''​exp'',''​log'',''​sqrt''​ et enfin élévation à la puissance 2. Comme notre générateur de nombre aléatoire ​//tire// entre **0** et **1**, nous devrions retrouver notre nombre initial (modulo les approximations).+Nous allons intégrer dans ce programme la fonction empilant successivement les 16 opérations ​suivantes ​: ''​cos'',''​arccos'',''​sin'',''​arcsin'',''​tan'',''​arctan'',''​cosh'',''​arccosh'',''​sinh'',''​arcsinh'',''​tanh'',''​arctanh'',''​exp'',''​log'',''​sqrt''​ et enfin élévation à la puissance 2. Comme notre générateur de nombres aléatoires ​//tire// entre **0** et **1**, nous devrions retrouver notre nombre initial (modulo les approximations).
  
-Cette fonction, nommée ''​MySillyFunction''​ devra être intégrée en Python natif et dans le noyau OpenCL. Lors de l'​addition des deux vecteurs, nous appliquerons cette fonction aux éléments de **a** et **b**.+Cette fonction, nommée ''​MySillyFunction''​ devra être intégrée en Python natif et dans le noyau OpenCL. Lors de l'​addition des deux vecteurs, nous appliquerons cette fonction aux éléments de **a** et **b** avant leur addition.
  
 De plus, de manière à juger plus finement des opérations nécessaires en OpenCL, nous allons intrumenter la fonction d'​appel pour juger du temps passé à l'​exécution dans chacune d'​elle. De plus, de manière à juger plus finement des opérations nécessaires en OpenCL, nous allons intrumenter la fonction d'​appel pour juger du temps passé à l'​exécution dans chacune d'​elle.
Ligne 604: Ligne 614:
  
 <note warning>​**Exercice #2.4 : ** <note warning>​**Exercice #2.4 : **
- 
   - Modifiez ''​MySteps_2.py''​ suivant les 8 spécifications ci-dessus   - Modifiez ''​MySteps_2.py''​ suivant les 8 spécifications ci-dessus
   - Exécutez le programme pour une taille de **32** (soit **2^5**)   - Exécutez le programme pour une taille de **32** (soit **2^5**)
-    - sur le GPU le plus //performant//+    - sur la GPU la plus //performante//
     - sur l'​implémentation CPU la plus //​efficace//​ : l'​Intel     - sur l'​implémentation CPU la plus //​efficace//​ : l'​Intel
   - Sauvegardez la sortie des deux exécutions précédentes   - Sauvegardez la sortie des deux exécutions précédentes
Ligne 614: Ligne 623:
   - Que constatez-vous sur la durée de la synthèse OpenCL   - Que constatez-vous sur la durée de la synthèse OpenCL
   - Exécutez le programme pour des tailles de vecteurs de **32** à **33554432**   - Exécutez le programme pour des tailles de vecteurs de **32** à **33554432**
-    - sur le GPU le plus //performant//+    - sur la GPU la plus //performante//
     - sur l'​implémentation CPU la plus //​efficace//​ : l'​Intel     - sur l'​implémentation CPU la plus //​efficace//​ : l'​Intel
   - Analysez dans quelles situations des problèmes de produisent   - Analysez dans quelles situations des problèmes de produisent
Ligne 634: Ligne 643:
 Par exemple, sur la machine **gtxtitan** (déjà un peu ancienne), nous avons le tableau de résultats suivant : Par exemple, sur la machine **gtxtitan** (déjà un peu ancienne), nous avons le tableau de résultats suivant :
  
-Pour le GPU le plus performant, la GTX Titan avec 6GB de RAM :+Pour la GPU la plus performante, la GTX Titan avec 6GB de RAM :
 ^  Size  ^  NativeRate ​ ^  OpenCLRate ​ ^  Ratio  ^ ^  Size  ^  NativeRate ​ ^  OpenCLRate ​ ^  Ratio  ^
 ^  32|  248551| ​ 83|  0.000334|  ​ ^  32|  248551| ​ 83|  0.000334|  ​
Ligne 658: Ligne 667:
 ^  33554432| ​ 1484349| ​ 52485826| ​ 35.359492| ​ ^  33554432| ​ 1484349| ​ 52485826| ​ 35.359492| ​
  
-Pour le CPU en implémentation Intel :+Pour la CPU en implémentation Intel :
  
 ^  Size  ^  NativeRate ​ ^  OpenCLRate ​ ^  Ratio  ^ ^  Size  ^  NativeRate ​ ^  OpenCLRate ​ ^  Ratio  ^
Ligne 683: Ligne 692:
 ^  33554432| ​ 1474004| ​ 22517796| ​ 15.276618| ^  33554432| ​ 1474004| ​ 22517796| ​ 15.276618|
  
-Nous constatons que le gain du passage en OpenCL est significatif,​ autant sur CPU que sur GPU, si la taille des objets approche le million. Nous avons une accélération de 15 pour le CPU et de 35 sur le GPU. En augmentant la charge très significativement (par exemple en n'​appelant pas seulement une fois ''​MySillyFunction''​ mais 4 fois à la suite, le gain sur CPU passe à 21 tandis qu'il dépasse les 127 sur ce GPU !+Nous constatons que le gain du passage en OpenCL est significatif,​ autant sur CPU que sur GPU, si la taille des objets approche le million. Nous avons une accélération de 15 pour le CPU et de 35 sur GPU. En augmentant la charge très significativement (par exemple en n'​appelant pas seulement une fois ''​MySillyFunction''​ mais 4 fois à la suite, le gain sur CPU passe à 21 tandis qu'il dépasse les 127 sur cette GPU !
  
-De plus, quand nous regardons les durées d'​exécution des noyaux en OpenCL, elles sont //presque// marginales. Ainsi, pour qu'une exécution OpenCL soit //​efficace//,​ il faudra veiller à ce que le temps d'​exécution soit bien supérieur aux autre durées telles que les transferts de données entre hôte et périphérique ou l'​initialisation du périphérique de calcul. Le programme ''​PiXPU.py''​ illustre de manière parfaite cet équilibre à établir sur le nombre de tâches concurrentielles à lancer et la //​profondeur calculatoire//​ (ou l'//​intensité arithmétique//​) de chaque noyau.+De plus, quand nous regardons les durées d'​exécution des noyaux en OpenCL, elles sont //presque// marginales. Ainsi, pour qu'une exécution OpenCL soit //​efficace//,​ il faudra veiller à ce que le temps d'​exécution soit bien supérieur aux autres ​durées telles que les transferts de données entre hôte et périphérique ou l'​initialisation du périphérique de calcul. Le programme ''​PiXPU.py''​ illustre de manière parfaite cet équilibre à établir sur le nombre de tâches concurrentielles à lancer et la //​profondeur calculatoire//​ (ou l'//​intensité arithmétique//​) de chaque noyau.
  
 ===== Un intermède CUDA et son implémentation PyCUDA ===== ===== Un intermède CUDA et son implémentation PyCUDA =====
  
-Nvidia a ressenti tôt la nécessité d'​offrir une abstraction de programmation simple pour ses GPU. Elle a même sorti **cg-toolkit** dès 2002. IL faudra attendre l'​été 2007 pour un langage complet, seulement limité à quelques GPU de sa gamme.+Nvidia a ressenti tôt la nécessité d'​offrir une abstraction de programmation simple pour ses GPU. Elle a même sorti **cg-toolkit** dès 2002. Il faudra attendre l'​été 2007 pour un langage complet, seulement limité à quelques GPU de sa gamme.
  
-Aujourd'​hui,​ CUDA est omniprésent dans les librairies du constructeur mais aussi dans l'​immense majorité des autres développements. Cependant, son problème vient de l'​adhérence au constructeur : CUDA ne sert QUE pour Nvidia.+Aujourd'​hui,​ CUDA est omniprésent dans les librairies du constructeur mais aussi dans l'​immense majorité des autres développements. Cependant, son problème vient de l'​adhérence au constructeur : CUDA ne sert QUE pour Nvidia. Nous verrons que CUDA a aussi d'​autres inconvénient,​ mais à l'​usage.
  
-L'​impressionnant [[https://​mathema.tician.de/​aboutme/​|Andreas Kloeckner]] a aussi développé,​ en plus de PyOpenCL, PyCUDA pour exploiter CUDA à travers Python avec les mêmes appoches ​: c'est [[https://​documen.tician.de/​pycuda/​|PyCUDA]]. ​+L'​impressionnant [[https://​mathema.tician.de/​aboutme/​|Andreas Kloeckner]] a aussi développé,​ en plus de PyOpenCL, PyCUDA pour exploiter CUDA à travers Python avec des approches ​: c'est [[https://​documen.tician.de/​pycuda/​|PyCUDA]]. ​
  
 L'​exemple de la page précédente ressemble fortement à celui que nous modifions depuis le début de nos travaux pratiques. Nous allons l'​exploiter pour intégrer cette implémentation CUDA dans notre programme ''​MySteps_3.py''​ (copie de ''​MySteps_2.py''​). L'​exemple de la page précédente ressemble fortement à celui que nous modifions depuis le début de nos travaux pratiques. Nous allons l'​exploiter pour intégrer cette implémentation CUDA dans notre programme ''​MySteps_3.py''​ (copie de ''​MySteps_2.py''​).
Ligne 730: Ligne 739:
 ^  32768| ​ 947854851| ​ 101677| ^  32768| ​ 947854851| ​ 101677|
  
-Normalement,​ si l'​implémentation a été correcte, la partie CUDA fonctionne pour les tailles de vecteurs inférieures ou égales à 1024... Cette limitation est en fait dûe à une //​mauvaise//​ utilisation de CUDA. En effet, CUDA (et dans une moindre mesure OpenCL) comporte 2 étages de parallélisation. Sous OpenCL, ces étages sont les //Work Items// et les //​Threads//​. Sous CUDA, ces étages sont les //Blocks// et les //​Threads//​. Hors, dans les deux approches OpenCL et CUDA, l'​étage de parallélisation //Threads// est l'​étage le plus fin, destiné à paralléliser des exécutions éponymes de la programmation parallèle. Mais, comme dans leurs implémentations sur processeurs,​ la parallélisation par Threads exige une "​synchronisation"​. Sous les implémentations CUDA et OpenCL, le nombre de //threads// maximal sollicitable dans un appel est seulement 1024 !+Normalement,​ si l'​implémentation a été correcte, la partie CUDA fonctionne pour les tailles de vecteurs inférieures ou égales à 1024... Cette limitation est en fait dûe à une //​mauvaise//​ utilisation de CUDA. En effet, CUDA (et dans une moindre mesure OpenCL) comporte 2 //étages// de parallélisation. Sous OpenCL, ces étages sont les //Work Items// et les //​Threads//​. Sous CUDA, ces étages sont les //Blocks// et les //​Threads//​. Hors, dans les deux approches OpenCL et CUDA, l'​étage de parallélisation //Threads// est l'​étage le plus fin, destiné à paralléliser des exécutions éponymes de la programmation parallèle. Mais, comme dans leurs implémentations sur processeurs,​ la parallélisation par //Threads// exige une "​synchronisation"​. Sous les implémentations CUDA et OpenCL, le nombre de //threads// maximal sollicitable dans un appel est seulement 1024 !
  
 Cette limitation de 1024 //Threads// entre en contradiction avec le cadre d'​utilisation présenté sur les GPU qui veut que le nombre de tâches équivalentes à exécuter est de l'​ordre d'au moins plusieurs dizaines de milliers. Donc, il ne faut pas, dans un premier temps, exploiter les //Threads// en CUDA mais les //Blocks//. Cette limitation de 1024 //Threads// entre en contradiction avec le cadre d'​utilisation présenté sur les GPU qui veut que le nombre de tâches équivalentes à exécuter est de l'​ordre d'au moins plusieurs dizaines de milliers. Donc, il ne faut pas, dans un premier temps, exploiter les //Threads// en CUDA mais les //Blocks//.
Ligne 817: Ligne 826:
 Le lien **[[https://​fr.wikipedia.org/​wiki/​Transformation_de_Fourier_discr%C3%A8te|Wikipedia]]** contient tout ce qui est nécessaire à l'​implémentation de votre propre TF d'​abord en Python "​naïf",​ puis en Python Numpy, ensuite en Python PyOpenCL et enfin en Python CUDA. Le lien **[[https://​fr.wikipedia.org/​wiki/​Transformation_de_Fourier_discr%C3%A8te|Wikipedia]]** contient tout ce qui est nécessaire à l'​implémentation de votre propre TF d'​abord en Python "​naïf",​ puis en Python Numpy, ensuite en Python PyOpenCL et enfin en Python CUDA.
  
-Comme le veut la tradition, la DFT s'​applique sur un vecteur complexe comprenant donc parties réelle et imaginaire et offre un résultat dans l'​espace complexe. Les vecteurs ''​a_np''​ et ''​b_np''​ seront donc +Comme le veut la tradition, la DFT s'​applique sur un vecteur complexe comprenant donc parties réelle et imaginaire et offre un résultat dans l'​espace complexe. Les vecteurs ''​a_np''​ et ''​b_np''​ seront donc respectivement les parties réelles et imaginaires de notre vecteur d'​entrée.
  
 Pour cela, nous partons de ''​MySteps_5.py''​ que nous copions en ''​MyDFT_1.py''​. Nous pouvons dans un premier temps commenter toutes les parties que nous ne comptons pas exploiter, ou simplement ne pas les appeler dans la fin du programme. ​ Pour cela, nous partons de ''​MySteps_5.py''​ que nous copions en ''​MyDFT_1.py''​. Nous pouvons dans un premier temps commenter toutes les parties que nous ne comptons pas exploiter, ou simplement ne pas les appeler dans la fin du programme. ​
  
-Pour les valeurs ​//​unités// ​dans les vecteurs, les valeurs théoriques de leur DFT sont : +Pour des valeurs ​réelles et imaginaires fixées à **1** dans le vecteur complexe, les valeurs théoriques de leur DFT sont : 
   * identiques pour les parties réelles et imaginaires   * identiques pour les parties réelles et imaginaires
   * égales à **1** pour le premier élément   * égales à **1** pour le premier élément
Ligne 827: Ligne 836:
  
 Ainsi, pour implémenter une DFT "​naïve",​ nous devons : Ainsi, pour implémenter une DFT "​naïve",​ nous devons :
-  - commenter toutes les parties inutiles du programme ''​MyDFT.py''​+  - commenter toutes les parties inutiles du programme ''​MyDFT_1.py''​
   - initialiser les vecteurs ''​a_np''​ et ''​b_np''​ à ''​1''​   - initialiser les vecteurs ''​a_np''​ et ''​b_np''​ à ''​1''​
-  - initialiser les vecteurs ''​C_np''​ et ''​D_np''​ résultats+  - initialiser les vecteurs ''​C_np''​ et ''​D_np''​ résultats ​(ou références)
   - créer une fonction Python ''​MyDFT'' ​   - créer une fonction Python ''​MyDFT'' ​
     * arguments ''​x''​ et ''​y''​     * arguments ''​x''​ et ''​y''​
Ligne 861: Ligne 870:
   - copier la fonction ''​NumpyDFT''​ sur le modèle de ''​MyDFT''​   - copier la fonction ''​NumpyDFT''​ sur le modèle de ''​MyDFT''​
   - dans cette nouvelle fonction, réaliser les opérations suivantes :   - dans cette nouvelle fonction, réaliser les opérations suivantes :
-  - créer un vecteur ''​nj''​ correspondant à l'argmument ​des **cos** et **sin** divisé par **i**+  - créer un vecteur ''​nj''​ correspondant à l'argument ​des **cos** et **sin** divisé par **i**
     * l'​exploitation de ''​numpy.multiply''​ est suggérée     * l'​exploitation de ''​numpy.multiply''​ est suggérée
   - créer l'​élément ''​X[i]''​ par l'​enchaînement des opérations :   - créer l'​élément ''​X[i]''​ par l'​enchaînement des opérations :
Ligne 884: Ligne 893:
 </​note>​ </​note>​
  
-Nous constatons que l'​exploitation des fonctions //​broadcast//​ est infiniment plus efficace que l'​implémentation naïve. Cependant, une observation des résultats laisse un tantinet perplexe sur les calculs. En effet, pour une exécution sur des vecteurs de tail 1024, nous avons :<​code>​+Nous constatons que l'​exploitation des fonctions //​broadcast//​ est infiniment plus efficace que l'​implémentation naïve. Cependant, une observation des résultats laisse un tantinet perplexe sur la précision des opération. En effet, pour une exécution sur des vecteurs de tail 1024, nous avons :<​code>​
 Size of vectors set to 1024 Size of vectors set to 1024
 Performing naive implementation Performing naive implementation
Ligne 896: Ligne 905:
 Les résultats par la méthode naïve semblent être plus précis (attention cependant, nous avons forcé les calculs sur des flottants 32 bits). Cela suggère qu'un contrôle calculatoire est plus que jamais nécessaire,​ quelle que soit la méthode exploitée, en Python ou autre. Les résultats par la méthode naïve semblent être plus précis (attention cependant, nous avons forcé les calculs sur des flottants 32 bits). Cela suggère qu'un contrôle calculatoire est plus que jamais nécessaire,​ quelle que soit la méthode exploitée, en Python ou autre.
  
-L'​utilisation de Numba offre une possibilité de parallélisation comparable à [[https://​fr.wikipedia.org/​wiki/​OpenMP|OpenMP]]. Avec une directive préfixant la fonction et quelques modifications,​ il est possible (normalement simplement) de paralléliser l'​exécution d'une boucle sur plusieurs coeurs ​ou envoyer l'​exécution de la boucle sur un périphérique externe. Nous l'​utiliserons que la parallélisation sur plusieurs coeurs.+L'​utilisation de Numba offre une possibilité de parallélisation comparable à [[https://​fr.wikipedia.org/​wiki/​OpenMP|OpenMP]]. Avec une directive préfixant la fonction et quelques modifications,​ il est possible (normalement simplement) de paralléliser l'​exécution d'une boucle sur plusieurs coeurs ​voire envoyer l'​exécution de la boucle sur un périphérique externe. Nous l'​utiliserons que la parallélisation sur plusieurs coeurs.
  
 Dans notre cas, il suffira de : Dans notre cas, il suffira de :
Ligne 929: Ligne 938:
 </​code>​ </​code>​
  
-Nous disposons également d'un message d'​erreur mais pas vraiment grave.+Nous disposons également d'un message d'​erreur mais pas vraiment grave... Ca fonctionne quand même ;-)
  
-Pour l'​implémentation OpenCL, la version "​naïve"​ de l'​implémentation va servir. Pour cela, il suffit de reprendre la définition de la méthode naïve et de l'​implémenter en C dans un noyau OpenCL. A noter que Pi n'​étant dans une variable définie, il faut explicitement la détailler. Autre détail important : le //cast//. De manière a éviter tout effet de bord, il est fortement recommandé de //caster// les opérations dans la précision flottante ​souhaiter ​pour des opérations sur des indices entiers.+Pour l'​implémentation OpenCL, la version "​naïve"​ de l'​implémentation va servir. Pour cela, il suffit de reprendre la définition de la méthode naïve et de l'​implémenter en C dans un noyau OpenCL. A noter que Pi n'​étant dans une variable définie, il faut explicitement la détailler ​dans le noyau OpenCL. Autre détail important : le //cast//. De manière a éviter tout effet de bord, il est fortement recommandé de //caster// les opérations dans la précision flottante ​souhaitée ​pour des opérations sur des indices entiers.
  
 <note warning>​**Exercice #4.4 : implémentation Python OpenCL** <note warning>​**Exercice #4.4 : implémentation Python OpenCL**
Ligne 974: Ligne 983:
 La précision en OpenCL est comparable à la méthode native, bien meilleure que les méthodes Python Numpy ou Numba. La performance est en deça de la méthode Numpy. Par contre, dès que les vecteurs dépassent une certaine taille (8192 avec Numba et 2048 avec OpenCL), Numpy est largement battu. La précision en OpenCL est comparable à la méthode native, bien meilleure que les méthodes Python Numpy ou Numba. La performance est en deça de la méthode Numpy. Par contre, dès que les vecteurs dépassent une certaine taille (8192 avec Numba et 2048 avec OpenCL), Numpy est largement battu.
  
-Avec l'​implémentation OpenCL Intel :+Avec l'​implémentation OpenCL Intel sur CPU :
 ^  Size  ^  NumpyRate ​ ^  NumbaRate ​ ^  OpenCL Rate  ^ ^  Size  ^  NumpyRate ​ ^  NumbaRate ​ ^  OpenCL Rate  ^
 ^  64|  15225| ​ 24|  186|  ​ ^  64|  15225| ​ 24|  186|  ​
Ligne 988: Ligne 997:
 ^  65536| ​ 221|  1212|  9497|  ​ ^  65536| ​ 221|  1212|  9497|  ​
  
-Avec l'​implémentation OpenCL sur le GPU :+Avec l'​implémentation OpenCL sur GPU :
 ^  Size  ^  NumpyRate ​ ^  NumbaRate ​ ^  OpenCL Rate  ^ ^  Size  ^  NumpyRate ​ ^  NumbaRate ​ ^  OpenCL Rate  ^
 ^  64|  15117| ​ 25|  204|  ​ ^  64|  15117| ​ 25|  204|  ​
Ligne 1050: Ligne 1059:
  
 Nous constatons que le l'​efficacité de CUDA est presque double de celle OpenCL. Nous constatons que le l'​efficacité de CUDA est presque double de celle OpenCL.
 +
 +Voyons si cette performance se confirme pour toutes les tailles de vecteurs.
  
 ^  Size  ^  NumpyRate ​ ^  NumbaRate ​ ^  OpenCL Rate  ^  CUDA Rate  ^ ^  Size  ^  NumpyRate ​ ^  NumbaRate ​ ^  OpenCL Rate  ^  CUDA Rate  ^
Ligne 1066: Ligne 1077:
 Nous constatons que CUDA monte plus rapidement //en charge// que OpenCL lorsque la taille du problème augmente. Cependant, CUDA attend une limite pour une taille de 2048 puis régresse drastiquement ensuite alors que OpenCL sa progression jusqu'​à une taille de 16384. Nous constatons que CUDA monte plus rapidement //en charge// que OpenCL lorsque la taille du problème augmente. Cependant, CUDA attend une limite pour une taille de 2048 puis régresse drastiquement ensuite alors que OpenCL sa progression jusqu'​à une taille de 16384.
  
-Pour CUDA, cela montre que nous sommes arrivés à saturation de l'​exploitation du premier étage de parallélisme avec les ''​grid'' ​: il faut maintenant exploiter les ''​thread'' ​de manière concomitante. L'​exemple ''​MyDFT_5b.py''​ illustre cette exploitation hybride. Les résultats pour une exploitation de **1024** //threads// (donc une taille de vecteur complexe de 1024) parlent d'​eux-mêmes :+Pour CUDA, cela montre que nous sommes arrivés à saturation de l'​exploitation du premier étage de parallélisme avec les //​blocks// ​: il faut maintenant exploiter les //​threads// ​de manière concomitante. L'​exemple ''​MyDFT_5b.py''​ illustre cette exploitation hybride. Les résultats pour une exploitation de **1024** //threads// (donc une taille de vecteur complexe de 1024) parlent d'​eux-mêmes :
  
 ^  Size  ^  NumpyRate ​ ^  NumbaRate ​ ^  OpenCL Rate  ^  CUDA Rate  ^ ^  Size  ^  NumpyRate ​ ^  NumbaRate ​ ^  OpenCL Rate  ^  CUDA Rate  ^
Ligne 1077: Ligne 1088:
 ^  65536| ​ 221|  1214|  11162| ​ 13446|  ​ ^  65536| ​ 221|  1214|  11162| ​ 13446|  ​
  
-Dans ce cas, CUDA est toujours plus performant que OpenCL mais la contrainte reste de pouvoir exploiter efficacement ces deux étages de parallélisme. Cette différence d'​efficacité n'est pas systématique : nous réalisons d'​abord qu'​elle dépend du système considéré mais cela va également complètement dépendre de l'​architecture interne ​du GPU, donc sa génération,​ son nombre de coeurs CUDA, sa mémoire, etc... ​+Dans ce cas, CUDA est toujours plus performant que OpenCL mais la contrainte reste de pouvoir exploiter efficacement ces deux étages de parallélisme. Cette différence d'​efficacité n'est pas systématique : nous réalisons d'​abord qu'​elle dépend du système considéré mais cela va également complètement dépendre de l'​architecture interne ​de la GPU, donc sa génération,​ son nombre de coeurs CUDA, sa mémoire, etc... ​
  
 L'​exemple précédent était exécuté sur une **GTX Titan** avec circuit Kepler datant de 2013.  L'​exemple précédent était exécuté sur une **GTX Titan** avec circuit Kepler datant de 2013. 
Ligne 1101: Ligne 1112:
 ^  65536| ​ 715|  6252|  117873| ​ 179320| ^  65536| ​ 715|  6252|  117873| ​ 179320|
  
-En conclusion de cette partie, ​l'approche progressive qui consiste de partir d'​abord d'une implémentation "​naïve"​ agnostique à tout langage, puis d'​exploiter les spécificités des uns ou des autres (comme les //​broadcast//​ Numpy ou la parallélisation par Numba), ensuite de construire avec Python/​OpenCL un modèle qui s'​exécutera partout (sur CPU ou GPU), enfin construire avec un Python/CUDA si le problème s'y prête, est une approche pertinente. A chaque étape, il est possible de s'​arrêter si la performance est en accord avec son //budget// de développement.+En conclusion de cette partie, ​une approche progressive qui consiste de partir d'​abord d'une implémentation "​naïve"​ agnostique à tout langage, puis d'​exploiter les spécificités des uns ou des autres (comme les //​broadcast//​ Numpy ou la parallélisation par Numba), ensuite de construire avec Python/​OpenCL un modèle qui s'​exécutera partout (sur CPU ou GPU), enfin construire avec un Python/CUDA si le problème s'y prête, est une approche pertinente. A chaque étape, il est possible de s'​arrêter si la performance est en accord avec son //budget// de développement.
  
 ===== Le choix du périphérique en OpenCL et CUDA ===== ===== Le choix du périphérique en OpenCL et CUDA =====
  
-Dans le chapitre 1, nous avons vu qu'il était possible de choisir le périphérique CUDA en //​inhibant//​ sa visibilité avec la vaniable ​d'​environnement ''​CUDA_VISIBLE_DEVICES''​. Seul le ou les périphériques sélectionnés étaient visibles. Cette méthode est cependant un peu brutale, surtout si nous souhaitons adresser plusieurs GPU dans notre exécution.+Dans le chapitre 1, nous avons vu qu'il était possible de choisir le périphérique CUDA en //​inhibant//​ sa visibilité avec la variable ​d'​environnement ''​CUDA_VISIBLE_DEVICES''​. Seul le ou les périphériques sélectionnés étaient visibles. Cette méthode est cependant un peu brutale, surtout si nous souhaitons adresser plusieurs GPU dans notre exécution.
  
 Dans le chapitre 2, nous avons vu que pour éviter d'​avoir à spécifier le périphérique OpenCL, nous pouvions exploiter la variable d'​environnement ''​PYOPENCL_CTX''​. C'​était effectivement utile mais nous n'​avions pas l'​assurance d'​exécuter //​réellement//​ sur ce périphérique sauf en regardant attentitivement les résultats des commandes ''​htop''​ ou ''​nvidia-smi dmon'''​. Dans le chapitre 2, nous avons vu que pour éviter d'​avoir à spécifier le périphérique OpenCL, nous pouvions exploiter la variable d'​environnement ''​PYOPENCL_CTX''​. C'​était effectivement utile mais nous n'​avions pas l'​assurance d'​exécuter //​réellement//​ sur ce périphérique sauf en regardant attentitivement les résultats des commandes ''​htop''​ ou ''​nvidia-smi dmon'''​.
Ligne 1111: Ligne 1122:
 Les méthodes présentées dans la suite ont l'​avantage d'​être systématiques et donc pourront être exploitées dans n'​importe quel programme PyOpenCL pour PyCUDA. Les méthodes présentées dans la suite ont l'​avantage d'​être systématiques et donc pourront être exploitées dans n'​importe quel programme PyOpenCL pour PyCUDA.
  
-A cela s'​ajoute également la possibilité d'​ajouter des options au lancement du programme, notamment pour spécifier ​son GPU. Dans les programmes de l'​archive **bench4gpu** en Python, la majorité dispose d'une option ''​-h''​ permettant de voir les options ainsi que de lister les périphériques OpenCL ou CUDA détectés.+A cela s'​ajoute également la possibilité d'​ajouter des options au lancement du programme, notamment pour spécifier ​sa GPU. Dans les programmes de l'​archive **bench4gpu** en Python, la majorité dispose d'une option ''​-h''​ permettant de voir les options ainsi que de lister les périphériques OpenCL ou CUDA détectés.
  
 L'​objectif est donc de reprendre notre exemple le plus abouti de notre DFT et d'y ajouter ces éléments. Pour cela, les programmes ''​PiXPU.py''​ et ''​TrouNoir.py''​ vont être explorés pour voir comment faire. L'​objectif est donc de reprendre notre exemple le plus abouti de notre DFT et d'y ajouter ces éléments. Pour cela, les programmes ''​PiXPU.py''​ et ''​TrouNoir.py''​ vont être explorés pour voir comment faire.
Ligne 1136: Ligne 1147:
   - Supprimer la sélection initiale d'​argument   - Supprimer la sélection initiale d'​argument
   - Inhiber pour l'​instant l'​exécution des fonctions   - Inhiber pour l'​instant l'​exécution des fonctions
-  - Intégrez les spécifications ci-dessus par de judicieux //​copier/​coller//​ de ''​PiXPU.py''​+  - Intégrez les spécifications ci-dessus par de judicieux //​copier/​coller//​ de ''​PiXPU.py''​
   - Vérifiez l'​option ''​-h''​   - Vérifiez l'​option ''​-h''​
 </​note>​ </​note>​
Ligne 1180: Ligne 1191:
   - Modifiez la fonction ''​OpenCLDFT''​ sur la base de fonction ''​MetropolisOpenCL''​ de ''​PiXPU.py''​   - Modifiez la fonction ''​OpenCLDFT''​ sur la base de fonction ''​MetropolisOpenCL''​ de ''​PiXPU.py''​
   - Exécutez le programme par défaut (sans option)   - Exécutez le programme par défaut (sans option)
-  - Exécutez le programme sur le second ​GPU+  - Exécutez le programme sur la seconde ​GPU
 </​note>​ </​note>​
  
Ligne 1204: Ligne 1215:
 </​code>​ </​code>​
  
-Pour une sollicitation ​du second ​GPU, la performance est moindre et c'est normal. ​Le GPU **Quadro K420** est très inférieur ​en performance à la **GTX Titan**.+Pour une sollicitation ​de la seconde ​GPU, la performance est moindre et c'est normal. ​La GPU **Quadro K420** est très inférieure ​en performance à la **GTX Titan**.
 <​code>​ <​code>​
 Device Selection : 1 Device Selection : 1
Ligne 1255: Ligne 1266:
     * rajouter la ligne ''​Context.detach()''​ ensuite     * rajouter la ligne ''​Context.detach()''​ ensuite
   - Exécutez le programme avec l'​option ''​-g CUDA''​   - Exécutez le programme avec l'​option ''​-g CUDA''​
-  - Exécutez le programme en sélectionnant ​le second ​GPU+  - Exécutez le programme en sélectionnant ​la seconde ​GPU
 </​note>​ </​note>​
  
Ligne 1308: Ligne 1319:
 </​code>​ </​code>​
  
-En lisant attentivement,​ nous découvrons que le compilateur **nvcc** embarqué ne supporte pas le GPU **Quadro K420** simplement parce qu'il est trop vieux ! Ainsi, **PyOpenCL** montre là aussi sa supériorité : non seulement PyOpenCL permet une exécution sans modification sur CPU ou GPU, de manière plus efficace qu'​avec Numpy ou Numba, mais en plus, sur GPU, elle offre moins de contraintes sur la distributions ​des tâches (pas de nécessité d'//​hybrider//​ son programme en //Blocks// et //​Threads//​) et une pérennité dans le temps, que ce soit pour les GPU très anciens ​ou très récents ​!+En lisant attentivement,​ nous découvrons que le compilateur **nvcc** embarqué ne supporte pas la GPU **Quadro K420** simplement parce qu'elle est trop vieille ​! Ainsi, **PyOpenCL** montre là aussi sa supériorité : non seulement PyOpenCL permet une exécution sans modification sur CPU ou GPU, de manière plus efficace qu'​avec Numpy ou Numba, mais en plus, sur GPU, elle offre moins de contraintes sur la distribution ​des tâches (pas de nécessité d'//​hybrider//​ son programme en //Blocks// et //​Threads//​) et une pérennité dans le temps, que ce soit pour les GPU très anciennes ​ou très récentes ​!
  
 Comme dernière modification sur notre , nous proposons de : Comme dernière modification sur notre , nous proposons de :
Ligne 1325: Ligne 1336:
 ===== Exploration avec le "​coeur"​ du GPU : xGEMM ===== ===== Exploration avec le "​coeur"​ du GPU : xGEMM =====
  
-Dans l'​introduction sur les GPU, il était présenté ​le GPU comme un "​gros"​ multiplicateur de matrices. ​+Dans l'​introduction sur les GPU, il était présenté ​la GPU comme un "​gros"​ multiplicateur de matrices. ​
  
 En effet, la méthode par //​shadering//​ exploitait de nombreuses multiplications matricielles pour générer une image numérique (CGI ou //Compute Generated Image//). Il n'est donc pas étonnant que les GPU soient, historiquement,​ plutôt "​efficaces"​ pour ce type de tâches : nous allons l'​évaluer. En effet, la méthode par //​shadering//​ exploitait de nombreuses multiplications matricielles pour générer une image numérique (CGI ou //Compute Generated Image//). Il n'est donc pas étonnant que les GPU soient, historiquement,​ plutôt "​efficaces"​ pour ce type de tâches : nous allons l'​évaluer.
Ligne 1455: Ligne 1466:
 Il faut donc prendre certaines précautions dans chaque évaluation de performances,​ notamment lorsque les durées d'​exécution sont trop courtes. Il faut donc prendre certaines précautions dans chaque évaluation de performances,​ notamment lorsque les durées d'​exécution sont trop courtes.
  
-Nous avons vu que plusieurs GPU peuvent coexister dans la machine. La question est de savoir lequel est sollicité lors d'un lancement de programme. Par défaut, avec les librairies CUDA, un seul GPU est sollicité, souvent ​le premier découvert. Pour savoir lequel a fait le travail, nous pouvons exploiter la commande ''​nvidia-smi''​ présentée ci-dessus pendant l'​exécution du programme.+Nous avons vu que plusieurs GPU peuvent coexister dans la machine. La question est de savoir lequel est sollicité lors d'un lancement de programme. Par défaut, avec les librairies CUDA, une seule GPU est sollicitée, souvent ​la première découverte. Pour savoir lequel a fait le travail, nous pouvons exploiter la commande ''​nvidia-smi''​ présentée ci-dessus pendant l'​exécution du programme.
  
 Dans le premier terminal qui nous sert à l'​exécution des programmes, nous avons : Dans le premier terminal qui nous sert à l'​exécution des programmes, nous avons :
Ligne 1497: Ligne 1508:
 Nous voyons que le GPU #0, identifié comme la GTX 1080 Ti, exécute 2 tâches : ''/​usr/​lib/​xorg/​Xorg''​ et ''​./​xGEMM_SP_cublas''​. Nous avons également l'​empreinte mémoire de chacun des processus : 36MiB pour le ''​Xorg''​ et 199MiB pour notre programme ''​xGEMM_SP_cublas''​. ​ Nous voyons que le GPU #0, identifié comme la GTX 1080 Ti, exécute 2 tâches : ''/​usr/​lib/​xorg/​Xorg''​ et ''​./​xGEMM_SP_cublas''​. Nous avons également l'​empreinte mémoire de chacun des processus : 36MiB pour le ''​Xorg''​ et 199MiB pour notre programme ''​xGEMM_SP_cublas''​. ​
  
-La question légitime est de se demander, dans le cas d'une machine multi-gpu, comment "​contrôler"​ sur quel GPU est exécuté ​le programme. Il existe des méthodes assez comparables à celles de OpenCL pour la découverte des périphériques,​ mais elles sont généralement peu exploitées dans les programmes. La technique la plus classique reste l'​utilisation d'une variable d'​environnement,​ laquelle va "​contraindre"​ l'​exploitation d'un (ou plusieurs) GPU(s) : ''​CUDA_VISIBLE_DEVICES''​.+La question légitime est de se demander, dans le cas d'une machine multi-gpu, comment "​contrôler"​ sur quele GPU est exécutée ​le programme. Il existe des méthodes assez comparables à celles de OpenCL pour la découverte des périphériques,​ mais elles sont généralement peu exploitées dans les programmes. La technique la plus classique reste l'​utilisation d'une variable d'​environnement,​ laquelle va "​contraindre"​ l'​exploitation d'un (ou plusieurs) GPU(s) : ''​CUDA_VISIBLE_DEVICES''​.
  
 Par exemple, si nous précisons que cette variable vaut ''​1'',​ le périphérique Nvidia ''#​1''​ sera le seul sollicité. Ainsi, en lançant la commande préfixée de cette variable valuée, nous avons : Par exemple, si nous précisons que cette variable vaut ''​1'',​ le périphérique Nvidia ''#​1''​ sera le seul sollicité. Ainsi, en lançant la commande préfixée de cette variable valuée, nous avons :
Ligne 1662: Ligne 1673:
 Nous allons tenter d'​exploiter un des exemples présentés dans les [[https://​www.tensorflow.org/​tutorials|tutoriels]] de [[https://​www.tensorflow.org/​|TensorFlow]]. Nous allons tenter d'​exploiter un des exemples présentés dans les [[https://​www.tensorflow.org/​tutorials|tutoriels]] de [[https://​www.tensorflow.org/​|TensorFlow]].
  
-L'​exploitation des GPU a littéralement "​explosé"​ lorsque le //Machine Learning// ou le //Deep Learning// sont devenus des modes. En effet, la puissance "​brute"​ des GPU peut enfin être exploitée sans trop de portage, notamment par l'​exploitation des librairies BLAS.+L'​exploitation des GPU a littéralement "​explosé"​ lorsque le //Machine Learning// ou le //Deep Learning// sont devenus des modes. En effet, la puissance "​brute"​ des GPU peut enfin être exploitée sans trop de portage, notamment par l'​exploitation des librairies BLAS ou cuDNN.
  
-L'​exemple sur lequel nous allons nous pencher est le [[https://​www.tensorflow.org/​tutorials/​images/​deep_cnn|DeepCNN]].+L'​exemple sur lequel nous allons nous pencher est le [[https://​www.tensorflow.org/​tutorials/​images/​cnn|DeepCNN]].
  
 L'​intégration de TensorFlow avec une exploitation des GPU est plutôt ardue à partir des sources, étant donné le nombre de dépendances. L'​approche [[https://​docs.conda.io/​en/​latest/​|Conda]] permet d'​installer un "​environnement système"​ bâti essentiellement autour d'​applications Python. Conda permet également à tout utilisateur de créer son propre environnement complet lui permettant un suivi personnel de ses outils. L'​intégration de TensorFlow avec une exploitation des GPU est plutôt ardue à partir des sources, étant donné le nombre de dépendances. L'​approche [[https://​docs.conda.io/​en/​latest/​|Conda]] permet d'​installer un "​environnement système"​ bâti essentiellement autour d'​applications Python. Conda permet également à tout utilisateur de créer son propre environnement complet lui permettant un suivi personnel de ses outils.
Ligne 1679: Ligne 1690:
   - préparez la variable d'​environnement ''​TIME''​   - préparez la variable d'​environnement ''​TIME''​
   - ouvrez un terminal et tapez ''​dstat''​ pour monitorer le système   - ouvrez un terminal et tapez ''​dstat''​ pour monitorer le système
-  - ouvrez un terminal et tapez ''​nvidia-smi dmon''​ pour le GPU+  - ouvrez un terminal et tapez ''​nvidia-smi dmon''​ pour la GPU
   - lancez un ''​ipython''​ dans un terminal   - lancez un ''​ipython''​ dans un terminal
   - appliquez ligne à ligne le tutoriel et regardez l'​activité réseau   - appliquez ligne à ligne le tutoriel et regardez l'​activité réseau
Ligne 1691: Ligne 1702:
   - inhibez les GPU Nvidia avec ''​CUDA_VISIBLE_DEVICES''​   - inhibez les GPU Nvidia avec ''​CUDA_VISIBLE_DEVICES''​
   - relancez le fichier préfixé de ''/​usr/​bin/​time python''​   - relancez le fichier préfixé de ''/​usr/​bin/​time python''​
-  - vérifiez que le GPU est inutilisé+  - vérifiez que la GPU est inutilisée
   - notez le temps écoulé (''​TIME Elapsed''​) pour cette troisième exécution   - notez le temps écoulé (''​TIME Elapsed''​) pour cette troisième exécution
-  - comparez les temps d'​exécution et sur l'​efficacité d'​usage ​du GPU+  - comparez les temps d'​exécution et sur l'​efficacité d'​usage ​de la GPU
 </​note>​ </​note>​
  
-En regardant l'​activité du GPU, il apparaît que le gain est substanciel par rapport à une "​petite"​ configuration GPU. Cependant, la nature du réseau créé n'​exploitait pas de manière optimale ​le GPU par rapport ​au CPU. Une petite modification de notre réseau va permettre de mettre cela en évidence, en modifiant le nombre de poids d'une des couches neuronales.+En regardant l'​activité du GPU, il apparaît que le gain est substanciel par rapport à une "​petite"​ configuration GPU. Cependant, la nature du réseau créé n'​exploitait pas de manière optimale ​la GPU par rapport ​à la CPU. Une petite modification de notre réseau va permettre de mettre cela en évidence, en modifiant le nombre de poids d'une des couches neuronales.
  
 <note warning>​**Exercice #7.2 :** <note warning>​**Exercice #7.2 :**
Ligne 1703: Ligne 1714:
   - relancez l'​apprentissage ''/​usr/​bin/​time python CIFAR10.py''​   - relancez l'​apprentissage ''/​usr/​bin/​time python CIFAR10.py''​
   - notez dès le début d'un cycle l'ETA (Estimate Time of Arrival) ​   - notez dès le début d'un cycle l'ETA (Estimate Time of Arrival) ​
-  - contrôlez l'​activité ​du GPU+  - contrôlez l'​activité ​de la GPU
   - arrêtez l'​apprentissage avec un **<​Ctrl><​C>​**   - arrêtez l'​apprentissage avec un **<​Ctrl><​C>​**
-  - inhibez ​le GPU+  - inhibez ​la GPU
   - relancez l'​apprentissage ''/​usr/​bin/​time python CIFAR10.py''​   - relancez l'​apprentissage ''/​usr/​bin/​time python CIFAR10.py''​
   - notez dès le début d'un cycle l'ETA   - notez dès le début d'un cycle l'ETA
Ligne 1712: Ligne 1723:
 </​note>​ </​note>​
  
-Sur la machine **k40** équipée d'une GPU **Tesla K40** ancienne et de deux CPU E5-2609v2, le ratio est de 15. Le plus intéressant vient de la comparaison avec la machine au CBP disposant des processeurs les plus performants : 2 AMD Epyc 7742 avec chacun 64 coeurs. Ces derniers sont 3x moins rapides que la K40 sur cette opération. Ainsi, même de vieux GPU (génération N-5) peuvent encore, dans des opérations de Machine Learning, s'​avérer efficaces, dès lors que les problèmes sont correctement dimensionnés pour eux.+Sur la machine **k40** équipée d'une GPU **Tesla K40** ancienne et de deux CPU E5-2609v2, le ratio est de 15. Le plus intéressant vient de la comparaison avec la machine au CBP disposant des processeurs les plus performants : 2 AMD Epyc 7742 avec chacun 64 coeurs. Ces derniers sont 3x moins rapides que la K40 sur cette opération. Ainsi, même de vieilles ​GPU (génération N-5) peuvent encore, dans des opérations de Machine Learning, s'​avérer efficaces, dès lors que les problèmes sont correctement dimensionnés pour elles.
  
 ==== Intégration et exploitation du code GENESIS ==== ==== Intégration et exploitation du code GENESIS ====
Ligne 1839: Ligne 1850:
  
 <note warning> <note warning>
-**Exercice #8.1 : exploration du code OpenCL**+**Exercice #10.1 : exploration du code OpenCL**
  
   * Repérez dans le programme source le **noyau** OpenCL réalisant le calcul   * Repérez dans le programme source le **noyau** OpenCL réalisant le calcul
Ligne 1926: Ligne 1937:
  
 <note warning> <note warning>
-**Exercice #8.2 : compilation et première exécution**+**Exercice #10.2 : compilation et première exécution**
  
   * Compilez le programme avec la ligne de compilation précisée ci-dessus   * Compilez le programme avec la ligne de compilation précisée ci-dessus
   * Exécutez le programme "à vide" et identifiez les périphériques   * Exécutez le programme "à vide" et identifiez les périphériques
-  * Exécutez le programme sur le premier ​GPU Nvidia que vous avez repéré+  * Exécutez le programme sur la première ​GPU Nvidia que vous avez repérée
 </​note>​ </​note>​
  
Ligne 1951: Ligne 1962:
  
 <note warning> <note warning>
-**Exercice #8.3 : exécution sur tous les périphériques pour un PR=1**+**Exercice #10.3 : exécution sur tous les périphériques pour un PR=1**
  
-  * Exécutez le programme sur tous (GPU & CPU) avec un nombre d'​itérations de 1 milliard+  * Exécutez le programme sur toutes ​(GPU & CPU) avec un nombre d'​itérations de 1 milliard
   * Repérez les éléments de **durée**, **itops** et le **inside**   * Repérez les éléments de **durée**, **itops** et le **inside**
   * Tracez l'​histogramme correspondant aux performances sur le modèle ci-dessus   * Tracez l'​histogramme correspondant aux performances sur le modèle ci-dessus
Ligne 1973: Ligne 1984:
  
 <note warning> <note warning>
-**Exercice #8.4 : exécution sur tous les périphériques pour un PR=1024**+**Exercice #10.4 : exécution sur tous les périphériques pour un PR=1024**
  
-  * Exécutez le programme sur tous (GPU & CPU) avec un nombre d'​itérations de 10 milliards+  * Exécutez le programme sur toutes ​(GPU & CPU) avec un nombre d'​itérations de 10 milliards
   * Repérez les éléments de **durée**, **itops** et **inside**   * Repérez les éléments de **durée**, **itops** et **inside**
   * Tracez l'​histogramme correspondant aux performances sur le modèle ci-dessus   * Tracez l'​histogramme correspondant aux performances sur le modèle ci-dessus
Ligne 1991: Ligne 2002:
 {{:​formation:​opencluster2_epu.png?​direct&​400|}} {{:​formation:​opencluster2_epu.png?​direct&​400|}}
  
-Ce graphique montre sans ambiguité la puissance "​brute"​ qu'​offre ​un GPU de gamer en comparaison de CPU traditionnel ​(33x dans la meilleure implémentation CPU, celle d'​Intel). Notons également que GPU n'est pas synonyme de puissance brute : la "​petite"​ Quadro K420, bien que "​professionnelle"​ présente des performances 77x inférieures.+Ce graphique montre sans ambiguité la puissance "​brute"​ qu'​offre ​une GPU de gamer en comparaison de CPU traditionnelle ​(33x dans la meilleure implémentation CPU, celle d'​Intel). Notons également que GPU n'est pas synonyme de puissance brute : la "​petite"​ Quadro K420, bien que "​professionnelle"​ présente des performances 77x inférieures.
  
 <note warning> <note warning>
-**Exercice #8.5 : exécution sur tous les périphériques pour un PR optimal**+**Exercice #10.5 : exécution sur tous les périphériques pour un PR optimal**
  
   * Reprenez les spécifications des GPU et isolez le nombre de //cuda cores//   * Reprenez les spécifications des GPU et isolez le nombre de //cuda cores//
Ligne 2000: Ligne 2011:
   * Repérez les éléments de **durée**, **itops** et **inside**   * Repérez les éléments de **durée**, **itops** et **inside**
   * Tracez l'​histogramme correspondant aux performances sur le modèle ci-dessus   * Tracez l'​histogramme correspondant aux performances sur le modèle ci-dessus
-  * Quel ratio de performance existe entre le GPU le plus puissant ​et la meilleure implémentation des CPU ?+  * Quel ratio de performance existe entre la GPU la plus puissante ​et la meilleure implémentation des CPU ?
 </​note>​ </​note>​
  
Ligne 2018: Ligne 2029:
 Nous avons présenté dans le cours qu'un mauvais choix de régime de parallélisme pouvait largement influencer la performance. Nous avons présenté dans le cours qu'un mauvais choix de régime de parallélisme pouvait largement influencer la performance.
  
-Par exemple, regardons pour la meilleure implémentation de CPU et pour le GPU le plus puissant, quelle influence a le choix du régime de parallélisme autour du régime de parallélisme optimal.+Par exemple, regardons pour la meilleure implémentation de CPU et pour la GPU la plus puissante, quelle influence a le choix du régime de parallélisme autour du régime de parallélisme optimal.
  
 <note warning> <note warning>
-**Exercice #8.6 : exécution sur tous les périphériques pour un PR optimal en double précision**+**Exercice #10.6 : exécution sur tous les périphériques pour un PR optimal en double précision**
  
   * Reprenez les expériences ci-dessus en précisant un calcul en double précision   * Reprenez les expériences ci-dessus en précisant un calcul en double précision
   * Tracez l'​histogramme avec tous les périphériques OpenCL   * Tracez l'​histogramme avec tous les périphériques OpenCL
-  * Quel ratio de performance existe entre le GPU le plus puissant ​et la meilleure implémentation des CPU ?+  * Quel ratio de performance existe entre la GPU la plus puissante ​et la meilleure implémentation des CPU ?
 </​note>​ </​note>​
  
Ligne 2114: Ligne 2125:
 === Examen du code source === === Examen du code source ===
  
-<note warning>​**Exercice #8.: récupération des éléments dans le code source**+<note warning>​**Exercice #11.: récupération des éléments dans le code source**
   * Editez le code source avec l'​outil ''​gedit''​   * Editez le code source avec l'​outil ''​gedit''​
   * Identifiez l'​appel de la procédure principale OpenCL : ligne   * Identifiez l'​appel de la procédure principale OpenCL : ligne
Ligne 2151: Ligne 2162:
 Nous observons que la scalabilité pour un code aussi simple n'est pas si triviale que cela à analyser. Il n'y a pas continuité en fonction de PR croissant. Notons une pseudo-période correspondant au nombre de coeurs physiques, avec des maximums locaux pour les multiples de cette valeur (le //handsaw curve effect//). Nous observons que la scalabilité pour un code aussi simple n'est pas si triviale que cela à analyser. Il n'y a pas continuité en fonction de PR croissant. Notons une pseudo-période correspondant au nombre de coeurs physiques, avec des maximums locaux pour les multiples de cette valeur (le //handsaw curve effect//).
  
-<note warning>​**Exercice #8.: étude de la scalabilité d'une implémentation CPU**+<note warning>​**Exercice #11.: étude de la scalabilité d'une implémentation CPU**
   * Identifiez avec ''​python3 PiXPU.py -h''​ un périphérique CPU   * Identifiez avec ''​python3 PiXPU.py -h''​ un périphérique CPU
   * Exécutez le d'un PR=1 à un PR égal à 8x le nombre de coeurs physiques   * Exécutez le d'un PR=1 à un PR égal à 8x le nombre de coeurs physiques
Ligne 2166: Ligne 2177:
 Nous pouvons constater que la scalabilité est très peu continue, encore moins que pour la scalabilité étudiée des CPU. Nous constatons également que des pseudo-lignes se chevauchent. Le PR optimal était autour de 4x le nombre de //cuda cores// et offrait une performance de **268 Gitops**. Nous pouvons constater que la scalabilité est très peu continue, encore moins que pour la scalabilité étudiée des CPU. Nous constatons également que des pseudo-lignes se chevauchent. Le PR optimal était autour de 4x le nombre de //cuda cores// et offrait une performance de **268 Gitops**.
  
-<note warning>​**Exercice #8.: étude de la scalabilité d'un GPU**+<note warning>​**Exercice #11.: étude de la scalabilité d'une GPU**
   * Identifiez avec ''​python3 PiXPU.py -h''​ un périphérique GPU   * Identifiez avec ''​python3 PiXPU.py -h''​ un périphérique GPU
   * Exécutez-le d'un PR=<​NbCudaCores>​ à un PR égal à 8x<​NbCudaCores>​ par pas de 128 en OpenCL   * Exécutez-le d'un PR=<​NbCudaCores>​ à un PR égal à 8x<​NbCudaCores>​ par pas de 128 en OpenCL
Ligne 2181: Ligne 2192:
 En relançant le calcul précédent,​ nous parvenons à **271 Gitops** soit plus que l'​implémentation OpenCL. En relançant le calcul précédent,​ nous parvenons à **271 Gitops** soit plus que l'​implémentation OpenCL.
  
-<note warning>​**Exercice #8.10 : étude de l'​implémentation CUDA autour du PR optimal**+<note warning>​**Exercice #11.: étude de l'​implémentation CUDA autour du PR optimal**
   * Identifiez avec ''​python3 PiXPU.py -h''​ le périphérique GPU déjà utilisé en CUDA   * Identifiez avec ''​python3 PiXPU.py -h''​ le périphérique GPU déjà utilisé en CUDA
   * Exécutez le avec le PR optimal des //Blocks// en CUDA   * Exécutez le avec le PR optimal des //Blocks// en CUDA
Ligne 2199: Ligne 2210:
 Alors que l'​optimum de performance est atteint autour d'un PR de 14336 avec **258 Gitops**, nous n'​obtenons un Itops que de **8.5 Gitops** (soit 30x moins) sur 5 valeurs particulières : 14321, 14323, 14327, 14341, 14347. Le point commun entre ces valeurs de PR est à rechercher sur le site [[http://​www.math.com/​students/​calculators/​source/​prime-number.htm|de mathématiques]] Alors que l'​optimum de performance est atteint autour d'un PR de 14336 avec **258 Gitops**, nous n'​obtenons un Itops que de **8.5 Gitops** (soit 30x moins) sur 5 valeurs particulières : 14321, 14323, 14327, 14341, 14347. Le point commun entre ces valeurs de PR est à rechercher sur le site [[http://​www.math.com/​students/​calculators/​source/​prime-number.htm|de mathématiques]]
  
-<note warning>​**Exercice #8.11 : étude de valeurs particulières de PR**+<note warning>​**Exercice #11.4 : étude de valeurs particulières de PR**
   * Exécutez ''​PiXPU.py''​ autour du PR égal à 4x le nombre de //cuda cores// (16 avant et 16 après)   * Exécutez ''​PiXPU.py''​ autour du PR égal à 4x le nombre de //cuda cores// (16 avant et 16 après)
   * Tracez les résultats avec GNUplot   * Tracez les résultats avec GNUplot
Ligne 2313: Ligne 2324:
  
 <note warning> <note warning>
-**Exercice #9.1 : étude du source de ''​NBody.py''​**+**Exercice #12.1 : étude du source de ''​NBody.py''​**
   * Editez le programme avec gedit   * Editez le programme avec gedit
   * Identifiez le bloc de noyaux OpenCL : lignes   * Identifiez le bloc de noyaux OpenCL : lignes
Ligne 2339: Ligne 2350:
  
 <note warning> <note warning>
-**Exercice #9.2 : lancement de ''​NBody.py''​ pour 32768 particules**+**Exercice #12.2 : lancement de ''​NBody.py''​ pour 32768 particules**
   * Exécutez le programme pour tous les périphériques détectés   * Exécutez le programme pour tous les périphériques détectés
   * Ajoutez l'​option pour un calcul en 64 bits et réexécutez   * Ajoutez l'​option pour un calcul en 64 bits et réexécutez
   * Tracez les histogrammes de performances   * Tracez les histogrammes de performances
-  * Quel est le ratio entre le meilleur ​GPU et le meilleur ​en CPU en 32 bits +  * Quel est le ratio entre la meilleure ​GPU et la meilleure ​en CPU en 32 bits 
-  * Quel est le ratio entre le meilleur ​GPU et le meilleur ​en CPU en 64 bits+  * Quel est le ratio entre la meilleure ​GPU et la meilleure ​en CPU en 64 bits
   * Quel est le ratio pour un même périphérique entre 32 et 64 bits ?   * Quel est le ratio pour un même périphérique entre 32 et 64 bits ?
 </​note>​ </​note>​
Ligne 2364: Ligne 2375:
 {{ :​formation:​nbody_007.png?​400 |}} {{ :​formation:​nbody_007.png?​400 |}}
  
-<note warning>​**Exercice #9.3 : lancement de ''​NBody.py''​ en mode ''​-g''​** +<note warning>​**Exercice #12.3 : lancement de ''​NBody.py''​ en mode ''​-g''​** 
-  * Exécutez le programme pour le meilleur des CPU sur 8192 particules+  * Exécutez le programme pour la meilleure implémentation sur CPU sur 8192 particules
   * Appuyez sur ''​s''​ pour passer des positions aux vitesses   * Appuyez sur ''​s''​ pour passer des positions aux vitesses
   * Utilisez les flèches pour les opérations de rotations   * Utilisez les flèches pour les opérations de rotations
   * Utilisez les <+> ou <-> pour les opérations de zoom ou dézoom   * Utilisez les <+> ou <-> pour les opérations de zoom ou dézoom
   * Sortez avec <Esc> et notez finalement la performance médiane en Squertz   * Sortez avec <Esc> et notez finalement la performance médiane en Squertz
-  * Exécutez le programme sur le GPU le plus puissant ​avec 8192 particules+  * Exécutez le programme sur la GPU la plus puissante ​avec 8192 particules
   * Sortez avec <Esc> et notez la performance médiane en Squertz   * Sortez avec <Esc> et notez la performance médiane en Squertz
-  * Exécutez le programme sur le GPU le plus puissant ​avec 8192 particules+  * Exécutez le programme sur la GPU la plus puissante ​avec 8191 particules
   * Sortez avec <Esc> et notez la performance médiane en Squertz   * Sortez avec <Esc> et notez la performance médiane en Squertz
   * Quel ratio entre Squertz existe entre 8192 et 8191 particules ?   * Quel ratio entre Squertz existe entre 8192 et 8191 particules ?
formation/etsn2022gpu.1658328789.txt.gz · Dernière modification: 2022/07/20 16:53 par equemene