Outils pour utilisateurs

Outils du site


lang:cpp:openmp

Ceci est une ancienne révision du document !


Compilateur

Pour activer l'option : -openmp pour GCC, /openmp pour Visual Studio (Projet|Propriétés|C/C++|Langage|Prise en charge de OpenMP).

OpenMP Application Programming Interface (Norme OpenMP v4.5) Archive du 09/03/2019

Guide into OpenMP: Easy multithreading programming for C++ Archive du 09/03/2019

Généralités de #pragma

Définitions

  • team : représente le groupe de threads utilisé par OpenMP.

Fonctions OpenMP

  • omp_get_thread_num() : le nième thread de la team à partir de 0.
  • omp_get_num_threads() : nombre de threads dans la team.

#pragma omp for

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.

#pragma omp for
for (int n = 0; n < 10; ++n)
  printf(" %d", n);

#pragma omp parallel

Doit être placé juste avant un bloc {}.

#pragma omp parallel
{
  for (int64_t i = 0; i < 4000000000; i++)
    {}
}

Le code va s'exécute en parallèle. Avec cette seule instruction, la boucle for est exécutée 8*4000000000.

#pragma omp parallel for

Doit être placé juste avant une boucle for.

Là, la boucle est découpée et exécutée en parallèle, ce qui est le but recherché.

#pragma omp parallel for
for (int64_t i = 0; i < 4000000000; i++)
  {}

C'est l'équivalent au code ci-dessous :

#pragma omp parallel
{
  #pragma omp for
  for (int64_t i = 0; i < 4000000000; i++)
    {}
}

#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 :

#pragma omp simd
for(int n=0; n<size; ++n)
  sinTable[n] = std::sin(2 * M_PI * n / size);

SIMD Vectorization with OpenMP Archive du 09/03/2019

Options

if

#pragma est exécutée si la condition est vraie.

extern int parallelism_enabled;
#pragma omp parallel for if(parallelism_enabled)

num_threads(X)

Indique le nombre de threads de la team.

#pragma omp parallel num_threads(3)

Gestion des variables

La variable est locale (private) à chaque thread :

  int n,m;
  #pragma omp parallel private(n)
    printf("%d %#010zx\n", omp_get_thread_num(), &n);
  printf("%#010zx\n", &m);

L'adresse de la variable n est différente pour chaque thread.

Rendu :

4 0x7f341ff72e14
0 0x7ffd31aadaf4
7 0x7f341e76fe14
3 0x7f3420773e14
1 0x7f3421775e14
6 0x7f341ef70e14
5 0x7f341f771e14
2 0x7f3420f74e14
0x7ffd31aadb44

On voit qu'un bloc de taille 0x801000 est alloué pour que thread.

Taille des blocs

  • static

Par défaut, tous les threads s'occupent de la même taille de données (static).

#pragma omp for schedule(static)
  • dynamic

Le thread interroge OpenMP pour savoir quelle plage de données il doit exécuter puis une fois terminée, il interroge OpenMP à nouveau.

Utile quand chaque élément dans la boucle n'a pas un temps d'exécution fixe ou quand on utilise ordered pour éviter de bloquer les threads suivants.

La taille de chaque bloc peut aussi être imposée.

#pragma omp for schedule(dynamic, 3)
  • guided

C'est un mix entre static et dynamic.

  • runtime

C'est OpenMP qui décide à l'exécution quelle est la meilleure stratégie à appliquer.

  • monolithic / nonmonolithic

monolithic : les blocs sont exécutés par ordre croissant, nonmonolithic : les blocs sont exécutés par ordre non forcément croissant,

<code c> #pragma omp for schedule(nonmonotonic:dynamic) </c>

lang/cpp/openmp.1552230645.txt.gz · Dernière modification : 2019/03/10 16:10 de root