web-dev-qa-db-fra.com

parallèle imbriqué openMP pour les boucles vs parallèle interne pour

Si j'utilise un parallèle imbriqué pour des boucles comme celle-ci:

#pragma omp parallel for schedule(dynamic,1)
for (int x = 0; x < x_max; ++x) {
    #pragma omp parallel for schedule(dynamic,1)
    for (int y = 0; y < y_max; ++y) { 
    //parallelize this code here
   }
//IMPORTANT: no code in here
}

est-ce équivalent à:

for (int x = 0; x < x_max; ++x) {
    #pragma omp parallel for schedule(dynamic,1)
    for (int y = 0; y < y_max; ++y) { 
    //parallelize this code here
   }
//IMPORTANT: no code in here
}

Le parallèle externe sert-il à autre chose qu'à créer une nouvelle tâche?

23
Scott Logan

Si votre compilateur prend en charge OpenMP 3.0, vous pouvez utiliser la clause collapse:

#pragma omp parallel for schedule(dynamic,1) collapse(2)
for (int x = 0; x < x_max; ++x) {
    for (int y = 0; y < y_max; ++y) { 
    //parallelize this code here
    }
//IMPORTANT: no code in here
}

Si ce n'est pas le cas (par exemple, seul OpenMP 2.5 est pris en charge), il existe une solution simple:

#pragma omp parallel for schedule(dynamic,1)
for (int xy = 0; xy < x_max*y_max; ++xy) {
    int x = xy / y_max;
    int y = xy % y_max;
    //parallelize this code here
}

Vous pouvez activer le parallélisme imbriqué avec omp_set_nested(1); et votre code omp parallel for Imbriqué fonctionnera, mais ce n'est peut-être pas la meilleure idée.

Au fait, pourquoi l'ordonnancement dynamique? Chaque itération de boucle est-elle évaluée en temps non constant?

39
Hristo Iliev

NON.

La première #pragma omp parallel créera une équipe de threads parallèles et le second essaiera ensuite de créer pour chacun des threads d'origine une autre équipe, c'est-à-dire une équipe d'équipes. Cependant, sur presque toutes les implémentations existantes, la deuxième équipe n'a qu'un seul thread: la deuxième région parallèle n'est essentiellement pas utilisée. Ainsi, votre code ressemble plus à l'équivalent de

#pragma omp parallel for schedule(dynamic,1)
for (int x = 0; x < x_max; ++x) {
    // only one x per thread
    for (int y = 0; y < y_max; ++y) { 
        // code here: each thread loops all y
    }
}

Si vous ne le souhaitez pas, mais que vous parallélisez uniquement la boucle interne, vous pouvez le faire:

#pragma omp parallel
for (int x = 0; x < x_max; ++x) {
    // each thread loops over all x
#pragma omp for schedule(dynamic,1)
    for (int y = 0; y < y_max; ++y) { 
        // code here, only one y per thread
    }
}
10
Walter