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:
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
if (code != cudaSuccess)
{
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
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:
gpuErrchk( cudaMalloc(&a_d, size*sizeof(int)) );
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 modifier gpuAssert
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:
kernel<<<1,1>>>(a);
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaDeviceSynchronize() );
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:
kernel<<<1,1>>>(a_d);
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaMemcpy(a_h, a_d, size * sizeof(int), cudaMemcpyDeviceToHost) );
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:
#include <assert.h>
#define cdpErrchk(ans) { cdpAssert((ans), __FILE__, __LINE__); }
__device__ void cdpAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
if (code != cudaSuccess)
{
printf("GPU kernel assert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) assert(0);
}
}
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.