Quand appeler cudadevicesynchroniser?

quand appelle-t-on cudaDeviceSynchronize fonction vraiment nécessaire?.

d'après ce que j'ai compris de la documentation de CUDA, les noyaux de CUDA sont asynchrones, donc il semble que nous devrions appeler cudaDeviceSynchronize après chaque lancement du noyau. Cependant, j'ai essayé le même code (formation de réseaux neuronaux) avec et sans cudaDeviceSynchronize, sauf un avant la mesure de temps. J'ai trouvé que j'obtiens le même résultat, mais avec une vitesse entre 7-12x (selon la matrice des tailles).

donc, la question Est s'il y a des raisons d'utiliser cudaDeviceSynchronize en dehors de la mesure du temps.

Par exemple:

  • est-il nécessaire avant de copier les données du GPU vers l'hôte avec <!--5?

  • Si je fais de la matrice des multiplications comme

    C = A * B
    D = C * F
    

devrais-je mettre cudaDeviceSynchronize entre les deux?

D'après mon expérience, il semble que non.

Pourquoi cudaDeviceSynchronize ralentir le programme à ce point?

44
demandé sur nbro 2012-08-09 21:25:41

3 réponses

bien que les lancements du noyau CUDA soient asynchrones, toutes les tâches liées au GPU placées dans un flux (qui est le comportement par défaut) sont exécutées de façon séquentielle.

ainsi, par exemple,

kernel1<<<X,Y>>>(...); // kernel start execution, CPU continues to next statement
kernel2<<<X,Y>>>(...); // kernel is placed in queue and will start after kernel1 finishes, CPU continues to next statement
cudaMemcpy(...); // CPU blocks until ememory is copied, memory copy starts only after kernel2 finishes

donc dans votre exemple il n'y a pas besoin de cudaDeviceSynchronize. Cependant, il pourrait être utile pour le débogage de détecter lequel de vos noyaux a causé une erreur (s'il y en a).

cudaDeviceSynchronize peut causer un certain ralentissement, mais 7-12x semble de trop. Peut-être il ya un problème avec le temps la mesure, ou peut-être les noyaux sont vraiment rapides, et la charge de synchronisation explicite est énorme par rapport au temps de calcul réel.

45
répondu aland 2012-08-09 18:22:48

une situation oùcudaDeviceSynchronize() est appropriée lorsque vous avez plusieurs cudaStream s en cours, et vous aimeriez qu'ils échangent des informations. Un cas réel de ce phénomène est le revenu parallèle dans les simulations quantiques de Monte Carlo. Dans ce cas, nous voulons nous assurer que chaque flux a terminé l'exécution d'un ensemble d'instructions et a obtenu quelques résultats avant qu'ils commencent à passer des messages les uns aux autres, ou nous finirions par passer des informations sur les ordures. La raison de cette utilisation la commande ralentit tellement le programme que cudaDeviceSynchronize() force le programme à attendre que toutes les commandes précédemment émises dans tous les flux sur l'appareil se terminent avant de continuer (à partir du Guide de programmation CUDA C). Comme vous l'avez dit, l'exécution du noyau est normalement asynchrone, donc pendant que le périphérique GPU exécute votre noyau, le CPU peut continuer à travailler sur d'autres commandes, donner plus d'instructions au périphérique, etc. au lieu d'attendre. Cependant, lorsque vous utilisez cette commande de synchronisation, le CPU est au lieu de cela forcé à l'inactivité jusqu'à ce que tout le travail GPU a terminé avant de faire quoi que ce soit d'autre. Ce comportement est utile lors du débogage, puisque vous pouvez avoir une défaillance de segfault se produisant à des moments apparemment "aléatoires" en raison de l'exécution asynchrone du code de périphérique (que ce soit dans un flux ou plusieurs). cudaDeviceSynchronize() va forcer le programme à s'assurer que les noyaux/memcpys du ou des flux sont complets avant de continuer, ce qui peut rendre plus facile de savoir où les accès illégaux se produisent (puisque l'échec va apparaître pendant la synchronisation).

14
répondu limes 2012-08-09 18:20:20

lorsque vous voulez que votre GPU commence à traiter certaines données, vous faites généralement une invocation kernale. Quand vous le faites, votre appareil (le GPU) commencera à faire ce que vous lui avez dit de faire. Cependant, contrairement à un programme séquentiel normal sur votre hôte (le CPU) continuera d'exécuter les prochaines lignes de code dans votre programme. cudadevicesynchroniser fait attendre l'hôte (le CPU) jusqu'à ce que l'appareil (le GPU) ont terminé l'exécution de tous les threads que vous avez commencé, et donc votre programme continuera comme si c'était normal d'un programme séquentiel.

dans les petits programmes simples, vous utilisez généralement cudadevicesynchroniser, lorsque vous utilisez le GPU pour faire des calculs, pour éviter les décalages entre le CPU demandant le résultat et le GPU finissant le calcul. Utiliser cudadevicesynchroniser rend plus facile de coder votre programme, mais il y a un inconvénient majeur: votre CPU est inactif tout le temps, tandis que le GPU fait le calcul. Par conséquent, dans le calcul de haute performance, vous souvent s'efforcer d'avoir votre CPU faisant des calculs pendant qu'il attend le GPU pour finir.

3
répondu Orpedo 2016-07-27 02:44:56