En parcourant les réponses et les commentaires sur les questions CUDA, et dans le wiki des balises CUDA , je constate qu'il est souvent suggéré que l'état de retour de chaque appel d'API devrait vérifier les erreurs. La documentation de l'API contient des fonctions commecudaGetLastError
que , cudaPeekAtLastError
et cudaGetErrorString
, mais quelle est la meilleure façon de les mettre ensemble pour les prises de manière fiable et des erreurs rapport sans nécessiter beaucoup de code supplémentaire?
cuda
error-checking
talonmies
la source
la source
getLastCudaError
etcheckCudaErrors
, qui font à peu près ce qui est décrit dans la réponse acceptée . Voir les exemples pour les démonstrations. Choisissez simplement d' installer les exemples avec la boîte à outils et vous l'avez.Réponses:
La meilleure façon de vérifier les erreurs dans le code API d'exécution est probablement de définir une fonction de gestionnaire de style d'assertion et une macro d'encapsuleur comme celle-ci:
Vous pouvez ensuite encapsuler chaque appel d'API avec la
gpuErrchk
macro, qui traitera le statut de retour de l'appel d'API qu'il encapsule, par exemple:S'il y a une erreur dans un appel, un message textuel décrivant l'erreur et le fichier et la ligne dans votre code où l'erreur s'est produite seront émis
stderr
et l'application se fermera. Vous pouvez éventuellement modifiergpuAssert
pour déclencher une exception plutôt que d'appelerexit()
une application plus sophistiquée si cela était nécessaire.Une deuxième question connexe est de savoir comment vérifier les erreurs dans les lancements du noyau, qui ne peuvent pas être directement encapsulées dans un appel de macro comme les appels d'API d'exécution standard. Pour les noyaux, quelque chose comme ceci:
vérifiera d'abord un argument de lancement non valide, puis forcera l'hôte à attendre jusqu'à ce que le noyau s'arrête et recherche une erreur d'exécution. La synchronisation peut être éliminée si vous avez un appel d'API de blocage ultérieur comme celui-ci:
dans ce cas, l'
cudaMemcpy
appel peut renvoyer soit des erreurs survenues lors de l'exécution du noyau, soit celles de la copie mémoire elle-même. Cela peut être déroutant pour le débutant, et je recommanderais d'utiliser une synchronisation explicite après un lancement du noyau pendant le débogage pour faciliter la compréhension des problèmes potentiels.Notez que lorsque vous utilisez CUDA Dynamic Parallelism , une méthodologie très similaire peut et doit être appliquée à toute utilisation de l'API d'exécution CUDA dans les noyaux de périphériques, ainsi qu'après tout lancement de noyau de périphériques:
la source
cudaDeviceReset()
avant de quitter également? Et une clause de désallocation de mémoire?La réponse de talonmies ci-dessus est un bon moyen d'interrompre une application de
assert
manière -style.Parfois, nous pouvons souhaiter signaler et récupérer une condition d'erreur dans un contexte C ++ dans le cadre d'une application plus grande.
Voici une façon raisonnablement concise de le faire en lançant une exception C ++ dérivée de l'
std::runtime_error
utilisationthrust::system_error
:Cela incorporera le nom de fichier, le numéro de ligne et une description en anglais du
cudaError_t
dans le.what()
membre de l'exception levée :Le résultat:
Un client de
some_function
peut distinguer les erreurs CUDA des autres types d'erreurs s'il le souhaite:Parce que
thrust::system_error
est unstd::runtime_error
, nous pouvons le gérer de la même manière d'une large classe d'erreurs si nous n'avons pas besoin de la précision de l'exemple précédent:la source
<thrust/system/cuda_error.h>
est désormais efficace<thrust/system/cuda/error.h>
.La méthode canonique C ++: ne vérifiez pas les erreurs ... utilisez les liaisons C ++ qui lèvent des exceptions.
J'étais irrité par ce problème; et j'avais l'habitude d'avoir une solution de fonction macro-wrapper comme dans les réponses de Talonmies et Jared, mais, honnêtement? Cela rend l'utilisation de l'API CUDA Runtime encore plus laide et semblable à C.
J'ai donc abordé cela d'une manière différente et plus fondamentale. Pour un exemple du résultat, voici une partie de l'
vectorAdd
exemple CUDA - avec une vérification complète des erreurs de chaque appel d'API d'exécution:Encore une fois - toutes les erreurs potentielles sont vérifiées, et une exception en cas d'erreur (mise en garde: si le noyau a causé une erreur après le lancement, il sera détecté après la tentative de copie du résultat, pas avant; pour vous assurer que le noyau a réussi, vous le feriez besoin de vérifier les erreurs entre le lancement et la copie avec un
cuda::outstanding_error::ensure_none()
commande).Le code ci-dessus utilise mon
Enveloppeurs Thin Modern-C ++ pour la bibliothèque API CUDA Runtime (Github)
Notez que les exceptions portent à la fois une explication de chaîne et le code d'état de l'API d'exécution CUDA après l'appel ayant échoué.
Quelques liens vers la façon dont les erreurs CUDA sont vérifiées automatiquement avec ces wrappers:
la source
La solution discutée ici a bien fonctionné pour moi. Cette solution utilise des fonctions cuda intégrées et est très simple à implémenter.
Le code correspondant est copié ci-dessous:
la source