num_threads est un mot clef permettant de limiter le nombre de threads à utiliser dans une boucle parallélisée avec openmp.
Il faut faire attention avant de l’utiliser car il induit parfois un overhead important, même si on veut utiliser moins de threads que le nombre maximum de threads openmp (défini par omp_set_num_threads). Le comportement décrit par la suite n’est pas tout le temps rencontré. Je n’ai pas vraiment d’explication sur les facteurs qui le déclenchent.
Exemple
// A l’initialisation de Myrian omp_set_num_threads(N); OPENMP_CHRONO_START_ID(NoMask0); #pragma omp parallel for for (int32_t j = 0; j<sliceSize; ++j) { } OPENMP_CHRONO_END_FOR_ID(NoMask0, sliceSize); OPENMP_CHRONO_START_ID(NoMask1); #pragma omp parallel for num_threads(6) for (int32_t j = 0; j<sliceSize; ++j) { } OPENMP_CHRONO_END_FOR_ID(NoMask1, sliceSize); OPENMP_CHRONO_START_ID(NoMask2); #pragma omp parallel for for (int32_t j = 0; j<sliceSize; ++j) { } OPENMP_CHRONO_END_FOR_ID(NoMask2, sliceSize);
Thread max (Myrian) | Computation time (s) | ||
NoMask0 | NoMask1 | NoMask2 | |
6 | 0.001162 | 0.001045 | 0.000956 |
16 | 0.003494 | 2.27518 | 1.967162 |
L’overhead dû à la modification locale du nombre de threads est supérieur à 2ms. De plus on a à nouveau un overhead à la boucle openmp suivante qui utilise un nombre de threads différent de 6. Du coup, il faut que le code parallélisé soit assez long pour que cela vaille le coup.
Explication
Lorsqu’on définit le nombre de threads max pour openmp, un pool de threads est créé (afin d’éviter de perdre du temps à créer des threads à chaque parallélisation). Malheureusement, lorsqu’on demande à utiliser moins de threads que cette valeur max, il semblerait qu’on détruit ce pool, puis en recréé un nouveau avec un nombre de threads inférieur (alors qu’il suffirait d’utiliser uniquement une partie du pool). Du coup, chaque modification du nombre de thread a un impact non négligeable sur les temps de calcul.
PS : On a exactement le même comportement si on utilise omp_set_num_threads.
PS2 : Les macros OPENMP_CHRONO_ servent juste à mesurer le temps de calcul.