Quelle est la différence entre “statique” et “dynamique” dans le calendrier d'OpenMP?
J'ai commencé à travailler avec OpenMP à l'aide de C++.
J'ai deux questions:
- Qu'est-ce que
#pragma omp for schedule
? - Quelle est la différence entre
dynamic
etstatic
?
S'il vous plaît, expliquer avec des exemples.
- Je pense que vous avez de la difficulté avec l'anglais, sens de l'annexe. Il se réfère à la façon dont le travail, c'est à dire les valeurs de la variable de boucle, est réparti entre les threads.
static
signifie qu'il est décidé, au début le thread qui va faire que les valeurs, où quedynamic
signifie que chaque thread va travailler sur un morceau de valeurs et ensuite prendre le prochain gros morceau qui n'a pas été travaillé par n'importe quel thread. Celui-ci permet un meilleur équilibre (dans le cas où les travaux varie entre les différentes valeurs de la variable de boucle), mais nécessite un peu de communication dessus.
Vous devez vous connecter pour publier un commentaire.
D'autres depuis ont répondu à la plupart de la question, mais je voudrais rappeler à certains cas précis où une planification particulière type est plus adapté que les autres. Annexe contrôle la manière dont les itérations de boucle sont divisés entre les threads. Choisir la bonne planification peut avoir un grand impact sur la vitesse de l'application.
static
annexe signifie que les itérations blocs sont cartographiés de manière statique à l'exécution de threads dans un round-robin". La bonne chose avec ordonnancement statique est que OpenMP moment de l'exécution de garanties que si vous avez deux boucles séparées avec le même nombre d'itérations et de les exécuter avec le même nombre de threads à l'aide d'ordonnancement statique, puis chaque thread recevrez exactement la même itération de la gamme(s) dans les deux parallèles régions. Ceci est particulièrement important sur les systèmes NUMA: si vous appuyez sur la mémoire dans la première boucle, il va résider sur le nœud NUMA où l'exécution du thread a été. Ensuite, dans la deuxième boucle le même thread peut accéder au même emplacement de mémoire plus rapide car il va résider sur le même nœud NUMA.L'imaginer il y a deux nœuds NUMA: le nœud 0 et le nœud 1, par exemple, un deux-socket Intel Nehalem conseil avec 4-core, dans les deux sockets. Puis threads 0, 1, 2, et 3 se trouvent sur le nœud 0 et fils 4, 5, 6, et 7 se trouvent sur le nœud 1:
Chaque noyau peut accéder à la mémoire à partir de chaque nœud NUMA, mais l'accès à distance est plus lent (1.5 x 1,9 x plus lent sur Intel) que le nœud local d'accès. Vous lancez quelque chose comme ceci:
4096 octets dans ce cas est la taille standard d'une page de la mémoire sous Linux sur x86 si énorme pages ne sont pas utilisées. Ce code permet de réinitialiser l'ensemble de la 32 Kio tableau
a
. Lemalloc()
appel juste des réserves de l'espace d'adressage virtuel mais ne fait pas de "toucher" la mémoire physique (ce qui est le comportement par défaut à moins qu'une autre version demalloc
est utilisé, par exemple, celui qui efface la mémoire commecalloc()
n'). Maintenant, ce tableau est contigus, mais seulement dans la mémoire virtuelle. Dans la mémoire physique de la moitié des il serait mentir dans le mémoire joint à la prise 0 et la moitié dans le mémoire joint à la prise 1. Il en est ainsi parce que les différentes parties sont remis à zéro par différents threads et les threads résident sur les différents cœurs et il ya quelque chose appelé premier contact de la politique NUMA qui signifie que les pages de mémoire sont alloués sur le nœud NUMA sur lequel le fil de cette première "touché" de la page de mémoire réside.Maintenant permet d'exécuter une autre boucle comme ceci:
Chaque thread va accéder à la déjà mappé en mémoire physique, et elle aura le même mappage de fil à la mémoire de la région comme l'une lors de la première boucle. Cela signifie que les fils aura uniquement accès à la mémoire située dans leurs locaux des blocs de mémoire qui sera rapide.
Maintenant, imaginez qu'un autre schéma de planification est utilisé pour la deuxième boucle:
schedule(static,2)
. Ce sera "chop" itération de l'espace en blocs de deux itérations et il y aura 4 blocs au total. Ce qui va arriver, c'est que nous aurons le fil de discussion suivant à l'emplacement mémoire de la cartographie (à travers le nombre d'itération):Deux mauvaises choses se produisent ici:
Ainsi, l'un des avantages pour l'utilisation de la planification statique est qu'il améliore la localité des accès mémoire. L'inconvénient est que les mauvais choix des paramètres de planification peut ruiner la performance.
dynamic
planification des travaux sur une base "premier arrivé, premier servi". Deux pistes avec le même nombre de threads peut (et probable) produire complètement différent "itération de l'espace" -> "threads" mappages comme on peut facilement le vérifier:(même comportement est observé lorsque
gcc
est utilisé à la place)Si l'exemple de code à partir de la
static
article a été exécuté avecdynamic
de la planification au lieu de cela, il y aura seulement 1/70 (1.4%) de chance que l'original de la localité serait préservé et 69/70 (98.6%) de chance que l'accès à distance allait se produire. Ce fait est souvent négligé et donc sous-optimale de ses performances.Il y a une autre raison de choisir entre
static
etdynamic
de la planification - l'équilibrage de la charge. Si chaque itération prend très différente de la moyenne du temps à remplir puis de travail élevée déséquilibre peut se produire dans le cas statique. Prenons comme exemple le cas où la durée d'exécution d'une itération croît linéairement avec le nombre d'itérations. Si l'itération de l'espace est divisé de manière statique entre les deux fils, la seconde va avoir trois fois plus de travail que la première, et, partant, pour les 2/3 du temps de calcul que le premier thread sera inactif. Calendrier dynamique introduit une charge supplémentaire, mais dans ce cas particulier, mènera à beaucoup mieux la distribution de charge de travail. Un type spécial dedynamic
la planification est leguided
où de plus en plus petites itération blocs sont donnés pour chaque tâche que le travail progresse.Depuis précompilés code peut être exécuté sur différentes plates-formes, ce serait bien si l'utilisateur peut contrôler la planification. C'est pourquoi OpenMP offre spéciale
schedule(runtime)
clause. Avecruntime
de planification le type est pris à partir du contenu de la variable d'environnementOMP_SCHEDULE
. Ceci permet de tester les différents types de planification sans avoir à recompiler l'application et aussi permet à l'utilisateur d'affiner sa plate-forme.Je pense que le malentendu vient du fait que vous manquez le point sur OpenMP.
Dans une phrase OpenMP permet d'exécuter des vous programme plus rapidement en activant le parallélisme.
Dans un programme de parallélisme peut être activée dans de nombreuses façons et celui de l'est par l'utilisation de threads.
Supposons que vous avez et de tableau:
et vous souhaitez incrément de tous les éléments par 1 dans ce tableau.
Si vous allez utiliser
cela signifie que chacun des fils sera attribué 5 contiguë itérations. Dans ce cas, le premier thread va prendre 5 numéros. Le deuxième on va prendre un autre 5 et ainsi de suite jusqu'à ce qu'il n'y a plus de données à traiter ou encore le nombre maximal de threads est atteint (généralement égal au nombre de cœurs). Le partage de la charge de travail est fait lors de la compilation.
En cas de
Le travail sera partagé entre les threads, mais cette procédure s'effectuera au moment de l'exécution. Ainsi, impliquant plus de surcharge. Deuxième paramètre spécifie la taille du bloc de données.
De ne pas être très familier pour OpenMP je risque de supposer que le type dynamique est plus approprié lors de la compilation du code va s'exécuter sur le système qui a une configuration différente que celle sur laquelle le code a été compilé.
Je voudrais recommander cette page à soufflet où il y a discuté des techniques utilisées pour la parallélisation du code, les conditions préalables et limites
https://computing.llnl.gov/tutorials/parallel_comp/
Des liens supplémentaires:
http://en.wikipedia.org/wiki/OpenMP
Différence entre statique et dynamique dans le calendrier d'openMP en C
http://openmp.blogspot.se/
La boucle schéma de partitionnement est différent. La statique planificateur aurait pour effet de diviser une boucle de N éléments en M sous-ensembles, et chaque sous-ensemble serait alors contenir strictement N/M éléments.
L'approche dynamique calcule la taille de la sous-ensembles à la volée, ce qui peut être utile si le sous-ensembles' des temps de calcul varient.
L'approche statique devrait être utilisé si le temps de calcul varient pas beaucoup.