9
votes

Comment sortir d'une boucle de fortrange parallèle (openmp) imbriquée idiomatiquement?

Code séquentiel d'ici:

  !$OMP PARALLEL private(i,j)
  !$OMP DO 
  do i = 1, n     
     !$OMP FLUSH(found)
     if (found) goto 10
     do j = i+1, n        
        if ("some_condition(i,j)") then
           !$OMP CRITICAL
           !$OMP FLUSH(found)
           if (.not.found) then           
              found = .true.
              result = "here's result"
           end if
           !$OMP FLUSH(found)
           !$OMP END CRITICAL
           goto 10
        end if
     end do
10   continue
  end do
  !$OMP END DO NOWAIT
  !$OMP END PARALLEL


0 commentaires

3 Réponses :


1
votes

Il semble $ opos do ne permet pas de sortir de la boucle plus tôt. Une alternative pourrait être de la mettre en œuvre à la main.

Donnez à chaque thread à chaque gamme de indices fixe fixe pour traiter

Suivant Guide dans OpenMP: programmation multithreading facile pour C ++ : xxx

update : remplacé goto par Quitter , introduit les résultats (code> tableau basé sur @ m. La réponse de qn .

Si la solution existe que cette approche est plus rapide que $ omp do en raison de la sortie antérieure.

donner à chaque fil un itération à la fois pour traiter

à l'aide de la directive de la tâche (suggérée par @ hautes performances marque ): xxx

Cette variante est 2 fois plus rapide sur mes tests que la version avec le externe -loop.


0 commentaires

1
votes

Il semble que votre code séquentiel ait une dépendance qui le rend inapproprié à être faite parallèle. Supposons qu'il y ait de multiples valeurs d'I & J qui rendent "certaines conditions" vraies - alors l'ordre d'exécution des boucles d'I & J DO Les boucles détermine laquelle de ces conditions se trouve en premier et définit la valeur du résultat, après quoi le retour La déclaration met fin à la recherche de cas supplémentaires je, j que "certaines conditions" est vrai. Dans le code séquentiel, les boucles DO sont toujours exécutées dans le même ordre. Le fonctionnement du programme est donc déterministe et identique des I & J qui rendent "certaines conditions" vraies seront toujours disponibles. Dans une version simultanée, diverses boucles que j'exécutent dans une commande non déterministe, de sorte que de courir pour exécuter différentes valeurs de je pourrait être la première valeur I qui trouve une "condition" vraie.

Peut-être que vous êtes en tant que programmeur savent qu'il n'y a qu'une seule valeur de I & J qui entraîne une véritable "condition"? Dans ce cas, le court-circuit, l'exécution semblerait bien. Mais la spécification OpenMP indique que "Aucune déclaration dans les boucles associées autres que les déclarations DO peuvent causer une branche Sorti des boucles "Alors, avoir le quelque chose dans la boucle interne abandonner la boucle de sortie n'est pas autorisé. Si c'est le cas, il n'y a toujours qu'une véritable" une condition ", vous pouvez simplement supprimer le" retour "et gaspiller la CPU le temps d'avoir des threads cherche "certaines conditions" est vrai après que l'un des cas a été trouvé. Cela pourrait toujours être plus rapide qu'un programme séquentiel. Avec une variable "Résultat" Stracter ", il n'est toujours pas non conforme, ayant une dépendance sur le ordre d'exécution. Vous pouvez le modifier vers une "réduction", résumer le résultat ou résultat de retour en tant que tableau 1-D de dimension (n). Si vous devez trouver la plus petite valeur de I qui a "une condition" vraie , vous pouvez obtenir cela à partir d'un résultat de la matrice à l'aide de la fonction InstroinSic Fortran Minloc.

Une solution avec de nombreuses directives "Flush" et "critiques" peut ne pas être plus rapide que la version séquentielle.

Mise à jour: en fonction de la clarification que plusieurs résultats sont possibles et que tout sera fait, un parallèle rencontré HOD serait de retourner les résultats de la plate-forme et de laisser le code séquentiel en choisir un "résultat" dans un tableau 1D plutôt qu'un refleer. Vous êtes autorisé à court-circuit le j-boucle interne car il n'est pas "associé" avec la directive "OMP faire", "Résultat" doit donc seulement être 1D, dimensionné en fonction de la plage de i. Alors quelque chose comme ceci: xxx


2 commentaires

Merci pour l'explication sur la raison pour laquelle OpenMP ne permet pas de sortir de la boucle plus tôt. J'ai mis à jour la question pour clarifier que tout résultat qui satisfait "certains_conditions" fera. BTW, enlever "Flush" de la boucle interne rend le programme 10 fois plus rapide.


@M. S. B.: Il est cher dans mon cas de itérer sur la boucle interne sans une nécessité stricte. La variante "Sortie intérieure" est ~ 150 fois plus lente que émulée à la variante de la main de ma réponse Stackoverflow.com/questions/2979760/...



1
votes

Une autre approche serait entièrement d'utiliser la construction de tâches qui fait partie de OpenMP 3.0. Ce que vous semble essayer de faire est de diviser vos boucles à travers les fils, calculez jusqu'à ce que tout fil trouve une réponse, puis tous les threads s'arrêtent. Le problème est que la nécessité d'avoir tous les threads vérifier un drapeau partagé est (a) tuer votre performance et (B) vous conduisant à des boucles laids avec des pauses et des cycles.

Je pense que @ M.S.B. La réponse donne de très bons conseils sur la manière d'adapter votre approche existante. Mais peut-être qu'un moyen plus naturel de s'attaquer au problème serait que le programme de créer un certain nombre de tâches (peut-être une pour chaque itération de votre boucle la plus interne) et de les envoyer à des threads de travailleurs. Une fois que tout fil de fil de thread, tous les threads peuvent être envoyés une tâche de finalisation et votre programme peut continuer.

Cela nécessiterait bien entendu plus de ré-écriture de votre programme et de faire une exécution séquentielle pire. Il exigera certainement que votre implémentation de OpenMP prend en charge la v3.0 de la norme.

Et vous aurez peut-être besoin de plus d'aide dans cette zone que je ne peux pas gérer, je viens de commencer à jouer avec des tâches openmp moi-même.


1 commentaires

Vous êtes correct: "Trouvez une réponse; arrêtez tous les threads" est une idée générale.