Dans OpenCL, ma compréhension est que vous pouvez utiliser la fonction barrier()
pour synchroniser les threads dans un groupe de travail. Je comprends (généralement) à quoi ils servent et quand les utiliser. Je suis également conscient que tous les threads d'un groupe de travail doivent atteindre la barrière, sinon il y a des problèmes. Cependant, chaque fois que j'ai essayé d'utiliser des barrières jusqu'à présent, cela semble entraîner soit le crash de mon pilote vidéo, soit un message d'erreur sur l'accès à une mémoire non valide. J'ai déjà vu cela sur 2 cartes vidéo différentes (1 ATI, 1 NVIDIA).
Donc, mes questions sont:
barrier(CLK_LOCAL_MEM_FENCE)
et barrier(CLK_GLOBAL_MEM_FENCE)
? J'ai lu la documentation, mais ce n'était pas clair pour moi.barrier(CLK_LOCAL_MEM_FENCE)
vs barrier(CLK_GLOBAL_MEM_FENCE)
?barrier()
avec le mauvais type de paramètre pourrait provoquer une erreur?Comme vous l'avez dit, les barrières ne peuvent synchroniser que les threads dans le même groupe de travail. Il n'y a aucun moyen de synchroniser différents groupes de travail dans un noyau.
Maintenant, pour répondre à votre question, la spécification n'était pas claire pour moi non plus, mais il me semble que la section 6.11.9 contient la réponse:
CLK_LOCAL_MEM_FENCE - La fonction de barrière videra toutes les variables stockées dans la mémoire locale ou mettra en file d'attente une clôture de mémoire pour garantir un ordre correct des opérations de mémoire dans la mémoire locale.
CLK_GLOBAL_MEM_FENCE - La fonction barrière mettra en file d'attente une clôture de mémoire pour garantir un ordre correct des opérations de mémoire sur la mémoire globale. Cela peut être utile lorsque des éléments de travail, par exemple, écrivent dans des objets de mémoire tampon ou d'image et souhaitent ensuite lire les données mises à jour.
Donc, à ma connaissance, vous devez utiliser CLK_LOCAL_MEM_FENCE lors de l'écriture et de la lecture dans le __local
espace mémoire et CLK_GLOBAL_MEM_FENCE lors de l'écriture et de la lecture dans le __global
espace mémoire.
Je n'ai pas testé si cela est plus lent, mais la plupart du temps, lorsque j'ai besoin d'une barrière et que j'ai un doute sur l'espace mémoire affecté, j'utilise simplement une combinaison des deux, à savoir:
barrier(CLK_LOCAL_MEM_FENCE | CLK_GLOBAL_MEM_FENCE);
De cette façon, vous ne devriez pas avoir de problème de commande de lecture/écriture de la mémoire (tant que vous êtes sûr que chaque thread du groupe passe par la barrière, mais vous en êtes conscient).
J'espère que cela aide.
Raviver un fil ancien ici. J'ai moi-même eu un peu de mal avec barrière ().
Concernant votre problème de crash, une cause potentielle pourrait être si votre barrière est à l'intérieur d'une condition. J'ai lu que lorsque vous utilisez la barrière, TOUS les éléments de travail du groupe doivent être en mesure d'atteindre cette instruction, sinon cela bloquera votre noyau, ce qui entraînera généralement un plantage.
if(someCondition){
//do stuff
barrier(CLK_LOCAL_MEM_FENCE);
//more stuff
}else{
//other stuff
}
Ma compréhension est que si un ou plusieurs éléments de travail satisfont à une condition, TOUS les éléments de travail doivent satisfaire à cette condition, ou il y en aura qui passeront la barrière. Les obstacles attendent que TOUS les éléments de travail atteignent ce point. Pour corriger le code ci-dessus, je dois le restructurer un peu:
if(someCondition){
//do stuff
}
barrier(CLK_LOCAL_MEM_FENCE);
if(someCondition){
//more stuff
}else{
//other stuff
}
Maintenant, tous les éléments de travail atteindront la barrière.
Je ne sais pas dans quelle mesure cela s'applique aux boucles; si un élément de travail rompt avec une boucle for, atteint-il des barrières? Je ne suis pas sûr.
MISE À JOUR: J'ai réussi à planter quelques programmes ocl avec une barrière dans une boucle for. Assurez-vous que tous les éléments de travail sortent de la boucle for en même temps - ou mieux encore, placez la barrière en dehors de la boucle.
(source: Heterogeneous Computing avec OpenCL Chapitre 5, p90-91)