Probablemente la mejor manera de verificar si hay errores en el código API de tiempo de ejecución es definir una función de controlador de estilo de aserción y una macro de envoltura como esta:
#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);
}
}
Luego, puede ajustar cada llamada a la API con la gpuErrchk
macro, que procesará el estado de retorno de la llamada a la API que se ajusta, por ejemplo:
gpuErrchk( cudaMalloc(&a_d, size*sizeof(int)) );
Si hay un error en una llamada, se emitirá un mensaje de texto que describe el error y el archivo y la línea en su código donde se produjo el error stderr
y la aplicación se cerrará. Podría modificarse gpuAssert
para generar una excepción en lugar de llamar exit()
a una aplicación más sofisticada si fuera necesario.
Una segunda pregunta relacionada es cómo verificar si hay errores en los lanzamientos de kernel, que no se pueden incluir directamente en una llamada de macro como las llamadas API estándar de tiempo de ejecución. Para los núcleos, algo como esto:
kernel<<<1,1>>>(a);
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaDeviceSynchronize() );
primero verificará si hay un argumento de inicio no válido, luego forzará al host a esperar hasta que el núcleo se detenga y verifique si hay un error de ejecución. La sincronización se puede eliminar si tiene una llamada de API de bloqueo posterior como esta:
kernel<<<1,1>>>(a_d);
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaMemcpy(a_h, a_d, size * sizeof(int), cudaMemcpyDeviceToHost) );
en cuyo caso la cudaMemcpy
llamada puede devolver errores que ocurrieron durante la ejecución del kernel o los de la copia de memoria. Esto puede ser confuso para el principiante, y recomendaría usar la sincronización explícita después del inicio del kernel durante la depuración para que sea más fácil entender dónde pueden surgir problemas.
Tenga en cuenta que cuando se utiliza el paralelismo dinámico de CUDA , una metodología muy similar puede y debe aplicarse a cualquier uso de la API de tiempo de ejecución de CUDA en los núcleos de dispositivos, así como después de que se inicie cualquier núcleo de dispositivos:
#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
ycheckCudaErrors
, que hacen más o menos lo que se describe en la respuesta aceptada . Ver las muestras para demostraciones. Simplemente elija instalar las muestras junto con el kit de herramientas y lo tendrá.