Outils pour utilisateurs

Outils du site


lang:cpp:openmp

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édentesRévision précédente
Prochaine révision
Révision précédente
lang:cpp:openmp [2019/03/11 00:24] – Ajout des exemples rootlang:cpp:openmp [2022/09/05 23:05] (Version actuelle) – [linear] : fix format root
Ligne 1: Ligne 1:
-====Compilateur====+====Compilation==== 
 +===Compilateur===
 Pour activer l'option : ''-openmp'' pour ''GCC'', ''/openmp'' pour Visual Studio (''Projet''|''Propriétés''|''C/C++''|''Langage''|''Prise en charge de OpenMP''). Pour activer l'option : ''-openmp'' pour ''GCC'', ''/openmp'' pour Visual Studio (''Projet''|''Propriétés''|''C/C++''|''Langage''|''Prise en charge de OpenMP'').
  
 [[https://www.openmp.org/wp-content/uploads/openmp-4.5.pdf|OpenMP Application Programming Interface (Norme OpenMP v4.5)]] {{ :lang:cpp:openmp:openmp-4.5.pdf |Archive du 09/03/2019}} [[https://www.openmp.org/wp-content/uploads/openmp-4.5.pdf|OpenMP Application Programming Interface (Norme OpenMP v4.5)]] {{ :lang:cpp:openmp:openmp-4.5.pdf |Archive du 09/03/2019}}
  
-[[https://bisqwit.iki.fi/story/howto/openmp/|Guide into OpenMP: Easy multithreading programming for C++]] {{ :lang:cpp:openmp:guide_into_openmp_easy_multithreading_programming_for_c_.mhtml |Archive du 09/03/2019}}+[[https://www.openmp.org/wp-content/uploads/openmp-examples-4.5.0.pdf|OpenMP Application Programming Interface Examples]], {{ :lang:cpp:openmp:openmp-examples-4.5.0.pdf |Archive du 11/02/2019}} 
 + 
 +[[https://bisqwit.iki.fi/story/howto/openmp/|Guide into OpenMP: Easy multithreading programming for C++]] {{ :lang:cpp:openmp:guide_into_openmp_easy_multithreading_programming_for_c_2019-10-16_15_43_58_.html |Archive du 10/02/2018 le 16/10/2019}} 
 + 
 +===CMake=== 
 + 
 +<code cmake> 
 +find_package(OpenMP) 
 +if(OpenMP_CXX_FOUND) 
 +  target_link_libraries(MyTarget PUBLIC OpenMP::OpenMP_CXX) 
 +endif() 
 +</code> 
 + 
 +[[https://cliutils.gitlab.io/modern-cmake/modern-cmake.pdf|Modern CMake]] {{ :lang:cpp:openmp:modern-cmake.pdf |Archive du 01/30/2020 le 04/03/2020}}
  
 ====Généralités de #pragma==== ====Généralités de #pragma====
Ligne 14: Ligne 28:
   * ''omp_get_num_threads()'' : nombre de threads dans la team.   * ''omp_get_num_threads()'' : nombre de threads dans la team.
  
-===#pragma omp for=== +====#pragma omp parallel====
-Doit être placé juste avant une boucle ''for''+
- +
-La boucle va être décomposée en n blocs (n étant le nombre de threads du CPU). L'ordre d'exécution des blocs est séquentiel car l'instruction ne précise pas l'exécution en parallèle. +
- +
-<code c> +
-#pragma omp for +
-for (int n 0; n < 10; ++n) +
-  printf(" %d", n); +
-</code> +
- +
-===#pragma omp parallel===+
 Doit être placé juste avant un bloc ''{}''. Doit être placé juste avant un bloc ''{}''.
  
Ligne 37: Ligne 40:
  
 Le code va s'exécute en parallèle. Avec cette seule instruction, la boucle for est exécutée 8*4000000000. Le code va s'exécute en parallèle. Avec cette seule instruction, la boucle for est exécutée 8*4000000000.
 +
 +====#pragma omp for====
 +===Généralités===
 +Doit être placé juste avant une boucle ''for''.
 +
 +La boucle va être décomposée en n blocs (n étant le nombre de threads du CPU). L'ordre d'exécution des blocs est séquentiel car l'instruction ne précise pas l'exécution en parallèle.
 +
 +<code c>
 +#pragma omp for
 +for (int n = 0; n < 10; ++n)
 +  printf(" %d", n);
 +</code>
  
 ===#pragma omp parallel for=== ===#pragma omp parallel for===
Ligne 60: Ligne 75:
 </code> </code>
  
-===#pragma omp simd=== 
-Cela parallélise les instructions de calcul pour utiliser au mieux les SSE* et autres. On peut autant y faire des calculs flottants qu'en entier. Le fonctionnement est similaire aux calculs CUDA : 
- 
-{{ :lang:cpp:openmp:simd-1.svg?600 |}} 
- 
-<code c> 
-#pragma omp simd 
-for(int n=0; n<size; ++n) 
-  sinTable[n] = std::sin(2 * M_PI * n / size); 
-</code> 
- 
-[[https://doc.itc.rwth-aachen.de/download/attachments/28344675/SIMD+Vectorization+with+OpenMP.PDF|SIMD Vectorization with OpenMP]] {{ :lang:cpp:openmp:simd_vectorization_with_openmp.pdf |Archive du 09/03/2019}} 
- 
-====Options==== 
 ===if=== ===if===
 ''#pragma'' est exécutée si la condition est vraie. ''#pragma'' est exécutée si la condition est vraie.
Ligne 303: Ligne 304:
  
 Dans notre cas particulier, l'utilisation de ''dynamic'' est plus lente car le processeur va passer plus de temps à changer de thread que d'exécuter le contenu de la boucle. Il faut donc que chaque itération de la boucle ait une charge assez soutenue. Dans notre cas particulier, l'utilisation de ''dynamic'' est plus lente car le processeur va passer plus de temps à changer de thread que d'exécuter le contenu de la boucle. Il faut donc que chaque itération de la boucle ait une charge assez soutenue.
 +
 +===collapse===
 +Fusionne les boucles imbriquées.
 +<code c>
 +#pragma omp parallel for collapse(2) num_threads(3)
 +for(int y=0; y<4; ++y)
 +  for(int x=0; x<3; ++x)
 +  {
 +    printf("%d %d %d\n", omp_get_thread_num(), x, y);
 +  }
 +</code>
 +
 +<WRAP center round important 60%>
 +Les bornes de la boucle intérieure ne doit pas dépendre de la variable de la boucle externe.
 +</WRAP>
 +
 +<code>
 +0 0 0
 +0 1 0
 +0 2 0
 +0 0 1
 +2 2 2
 +2 0 3
 +2 1 3
 +2 2 3
 +1 1 1
 +1 2 1
 +1 0 2
 +1 1 2
 +</code>
 +
 +===reduction===
 +Est utilisé si une variable commune est modifiée lors de la parallélisation.
 +
 +<code c>
 +int main()
 +{
 +int sum(0);
 +#pragma omp parallel for schedule(...) num_threads(3) reduction(+:sum)
 +for(int x=0; x<100000000; ++x)
 +{
 +  sum += 1;
 +}
 +printf("%d\n", sum);
 +}
 +</code>
 +
 +^''schedule''^Variable        ^''reduction''^Résultat ^Temps   ^
 +|static      |int             |non          |50231932 |0m0,431s|
 +|static      |int             |oui          |100000000|0m0,071s|
 +|static      |std::atomic<int>|non          |100000000|0m1,886s|
 +|dynamic     |int             |non          |51166934 |0m3,087s|
 +|dynamic     |int             |oui          |100000000|0m1,890s|
 +|dynamic     |std::atomic<int>|non          |100000000|0m3,812s|
 +
 +====#pragma omp sections====
 +Défini des blocs de code qui peuvent s'exécuter en parallèle dans la team. Il faut donc le coupler avec ''#pragma omp parallel''.
 +
 +Ci-dessous, les 3 blocs s'exécutent en parallèle.
 +
 +<code c>
 +#pragma omp parallel sections
 +{
 +  {
 +    Work1();
 +  }
 +  #pragma omp section
 +  {
 +    Work2();
 +    Work3();
 +  }
 +  #pragma omp section
 +  {
 +    Work4();
 +  }
 +}
 +</code>
 +
 +====#pragma omp simd====
 +[[https://doc.itc.rwth-aachen.de/download/attachments/28344675/SIMD+Vectorization+with+OpenMP.PDF|SIMD Vectorization with OpenMP]] {{ :lang:cpp:openmp:simd_vectorization_with_openmp.pdf |Archive du 09/03/2019}}
 +
 +Cela parallélise les instructions de calcul pour utiliser au mieux les SSE* et autres. On peut autant y faire des calculs flottants qu'en entier. Le fonctionnement est similaire aux calculs CUDA :
 +
 +{{ :lang:cpp:openmp:simd-1.svg |}}
 +
 +<code c>
 +#pragma omp simd
 +for(int n=0; n<size; ++n)
 +  sinTable[n] = std::sin(2 * M_PI * n / size);
 +</code>
 +
 +===aligned===
 +SSE2 a besoin que les variables soient alignées en multiple de 16 octets. On peut dire à OpenMP que les variables sont toujours correctement alignées. Mais dans le cas contraire, les calculs seront faux.
 +
 +On peut déclarer soit au niveau de la variable, soit au niveau de la fonction.
 +
 +<code c>
 +#pragma omp declare simd aligned(a,b:16)
 +void add_arrays(float *__restrict__ a, float *__restrict__ b)
 +{
 +  #pragma omp simd aligned(a,b:16)
 +  for(int n=0; n<8; ++n) a[n] += b[n];
 +}
 +</code>
 +
 +''%%__restrict__%%'' permet de dire que le contenu ne change pas et que personne ne pointe dessus sauf la variable utilisée.
 +
 +===safelen===
 +Limite le nombre de calculs en parallèle via ''simd''. Utile si deux tableaux se superposent.
 +
 +===simdlen===
 +Taille des blocs SIMD à calculer en même temps.
 +
 +===linear===
 +Incrémente pour chaque boucle une variable.
 +<code cpp>
 +#pragma omp simd linear(b:2)
 +for(int n=0; n<8; ++n) array[n] = b;
 +</code>
 +
 +Ne marche pas avec GCC 8.
 +
 +===uniform===
 +Indique d'une variable est une constante.
 +
 +====#pragma omp task====
 +Déclare des tâches qui seront exécutée dans un thread parallèle.
 +
 +On utilise ''taskwait'' pour attendre que les tâches soient terminées.
 +
 +====#pragma omp single====
 +Impose l'exécution d'un bloc par un seul thread. Ci-dessous, la boucle est exécutée une seule fois son contenu est exécuté en parallèle grâce à ''#pragma omp task''.
 +
 +<code c>
 +<#pragma omp parallel
 +{
 +  #pragma omp single
 +  {
 +    #pragma omp task
 +    {
 +      printf("%d\n", omp_get_thread_num());
 +    }
 +    #pragma omp task
 +    {
 +      printf("%d\n", omp_get_thread_num());
 +    }
 +    #pragma omp task
 +    {
 +      printf("%d\n", omp_get_thread_num());
 +    }
 +    #pragma omp taskwait
 +    printf("Fin %d\n", omp_get_thread_num());
 +  }
 +}
 +</code>
 +
 +====Bugs / messages d'erreur====
 +===Charger dynamiquement une DLL qui est liée à OpenMP===
 +
 +OpenMP gère ses threads comme Windows. Quand un thread a terminé ce qu'il avait à faire, il reste dans la ''pool'' et est stocké en vue d'une éventuelle réutilisation.
 +
 +Dans le cas de la DLL de OpenMP, si on décharge la DLL ayant chargé OpenMP et que le pool de threads n'est pas vide, il y a un crash.
 +
 +Solution : définir obligatoirement la variable d'environnement ''OMP_WAIT_POLICY'' à ''passive'' pour que la durée avant libération de la mémoire des threads après leur mort soit nulle.
 +
 +Selon le code source de gcc (''libgomp\env.c'') et la fonction ''parse_wait_policy'' :
 +
 +^''OMP_WAIT_POLICY''^Durée de vie du pool^
 +|Non défini.        | 3 ms               |
 +|''active''         | 5 minutes          |
 +|''passive''        | 0 ms               |
 +
 +[[https://stackoverflow.com/questions/34439956/vc-crash-when-freeing-a-dll-built-with-openmp|VC++: crash when freeing a DLL built with openMP]] {{ :lang:cpp:openmp:visual_c_-_vc_crash_when_freeing_a_dll_built_with_openmp_-_stack_overflow_2019-10-16_16_27_25_.html |Archive du 23/12/2015 le 16/10/2019}}
lang/cpp/openmp.1552260296.txt.gz · Dernière modification : 2019/03/11 00:24 de root