lang:cpp:openmp
Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
| lang:cpp:openmp [2019/03/11 00:24] – Ajout des exemples root | lang:cpp:openmp [2022/09/05 23:05] (Version actuelle) – [linear] : fix format root | ||
|---|---|---|---|
| Ligne 1: | Ligne 1: | ||
| - | ====Compilateur==== | + | ====Compilation==== |
| + | ===Compilateur=== | ||
| Pour activer l' | Pour activer l' | ||
| [[https:// | [[https:// | ||
| - | [[https:// | + | [[https:// |
| + | |||
| + | [[https:// | ||
| + | |||
| + | ===CMake=== | ||
| + | |||
| + | <code cmake> | ||
| + | find_package(OpenMP) | ||
| + | if(OpenMP_CXX_FOUND) | ||
| + | target_link_libraries(MyTarget PUBLIC OpenMP:: | ||
| + | endif() | ||
| + | </ | ||
| + | |||
| + | [[https:// | ||
| ====Généralités de #pragma==== | ====Généralités de #pragma==== | ||
| Ligne 14: | Ligne 28: | ||
| * '' | * '' | ||
| - | ===#pragma omp for=== | + | ====#pragma omp parallel==== |
| - | Doit être placé juste avant une boucle '' | + | |
| - | + | ||
| - | La boucle va être décomposée en n blocs (n étant le nombre de threads du CPU). L' | + | |
| - | + | ||
| - | <code c> | + | |
| - | #pragma omp for | + | |
| - | for (int n = 0; n < 10; ++n) | + | |
| - | printf(" | + | |
| - | </ | + | |
| - | + | ||
| - | ===#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' | Le code va s' | ||
| + | |||
| + | ====#pragma omp for==== | ||
| + | ===Généralités=== | ||
| + | Doit être placé juste avant une boucle '' | ||
| + | |||
| + | La boucle va être décomposée en n blocs (n étant le nombre de threads du CPU). L' | ||
| + | |||
| + | <code c> | ||
| + | #pragma omp for | ||
| + | for (int n = 0; n < 10; ++n) | ||
| + | printf(" | ||
| + | </ | ||
| ===#pragma omp parallel for=== | ===#pragma omp parallel for=== | ||
| Ligne 60: | Ligne 75: | ||
| </ | </ | ||
| - | ===#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 : | ||
| - | |||
| - | {{ : | ||
| - | |||
| - | <code c> | ||
| - | #pragma omp simd | ||
| - | for(int n=0; n<size; ++n) | ||
| - | sinTable[n] = std::sin(2 * M_PI * n / size); | ||
| - | </ | ||
| - | |||
| - | [[https:// | ||
| - | |||
| - | ====Options==== | ||
| ===if=== | ===if=== | ||
| ''# | ''# | ||
| Ligne 303: | Ligne 304: | ||
| Dans notre cas particulier, | Dans notre cas particulier, | ||
| + | |||
| + | ===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(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <WRAP center round important 60%> | ||
| + | Les bornes de la boucle intérieure ne doit pas dépendre de la variable de la boucle externe. | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | 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 | ||
| + | </ | ||
| + | |||
| + | ===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(+: | ||
| + | for(int x=0; x< | ||
| + | { | ||
| + | sum += 1; | ||
| + | } | ||
| + | printf(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ^'' | ||
| + | |static | ||
| + | |static | ||
| + | |static | ||
| + | |dynamic | ||
| + | |dynamic | ||
| + | |dynamic | ||
| + | |||
| + | ====#pragma omp sections==== | ||
| + | Défini des blocs de code qui peuvent s' | ||
| + | |||
| + | Ci-dessous, les 3 blocs s' | ||
| + | |||
| + | <code c> | ||
| + | #pragma omp parallel sections | ||
| + | { | ||
| + | { | ||
| + | Work1(); | ||
| + | } | ||
| + | #pragma omp section | ||
| + | { | ||
| + | Work2(); | ||
| + | Work3(); | ||
| + | } | ||
| + | #pragma omp section | ||
| + | { | ||
| + | Work4(); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ====#pragma omp simd==== | ||
| + | [[https:// | ||
| + | |||
| + | 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 : | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | <code c> | ||
| + | #pragma omp simd | ||
| + | for(int n=0; n<size; ++n) | ||
| + | sinTable[n] = std::sin(2 * M_PI * n / size); | ||
| + | </ | ||
| + | |||
| + | ===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, | ||
| + | void add_arrays(float *__restrict__ a, float *__restrict__ b) | ||
| + | { | ||
| + | #pragma omp simd aligned(a, | ||
| + | for(int n=0; n<8; ++n) a[n] += b[n]; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | '' | ||
| + | |||
| + | ===safelen=== | ||
| + | Limite le nombre de calculs en parallèle via '' | ||
| + | |||
| + | ===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; | ||
| + | </ | ||
| + | |||
| + | 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 '' | ||
| + | |||
| + | ====#pragma omp single==== | ||
| + | Impose l' | ||
| + | |||
| + | <code c> | ||
| + | <#pragma omp parallel | ||
| + | { | ||
| + | #pragma omp single | ||
| + | { | ||
| + | #pragma omp task | ||
| + | { | ||
| + | printf(" | ||
| + | } | ||
| + | #pragma omp task | ||
| + | { | ||
| + | printf(" | ||
| + | } | ||
| + | #pragma omp task | ||
| + | { | ||
| + | printf(" | ||
| + | } | ||
| + | #pragma omp taskwait | ||
| + | printf(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ====Bugs / messages d' | ||
| + | ===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 '' | ||
| + | |||
| + | 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' | ||
| + | |||
| + | Selon le code source de gcc ('' | ||
| + | |||
| + | ^'' | ||
| + | |Non défini. | ||
| + | |'' | ||
| + | |'' | ||
| + | |||
| + | [[https:// | ||
lang/cpp/openmp.1552260296.txt.gz · Dernière modification : de root
