Al revisar las respuestas y los comentarios sobre las preguntas de CUDA, y en el wiki de etiquetas de CUDA , veo que a menudo se sugiere que el estado de devolución de cada llamada a la API debe verificarse en busca de errores. La documentación de la API contiene funciones como cudaGetLastError
, cudaPeekAtLastError
y cudaGetErrorString
, pero ¿cuál es la mejor manera de poner éstos juntos para detectar los errores e informe de forma fiable sin requerir una gran cantidad de código extra?
cuda
error-checking
talonmies
fuente
fuente
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á.Respuestas:
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:
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: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 modificarsegpuAssert
para generar una excepción en lugar de llamarexit()
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:
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:
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:
fuente
cudaDeviceReset()
antes de salir también? ¿Y una cláusula para la desasignación de memoria?La respuesta anterior de talonmies es una buena manera de abortar una aplicación de una
assert
manera estilo.Ocasionalmente, podemos informar y recuperar una condición de error en un contexto C ++ como parte de una aplicación más grande.
Aquí hay una manera razonablemente breve de hacerlo lanzando una excepción C ++ derivada del
std::runtime_error
usothrust::system_error
:Esto incorporará el nombre de archivo, el número de línea y una descripción
cudaError_t
en inglés del.what()
miembro de la excepción lanzada :La salida:
Un cliente de
some_function
puede distinguir los errores de CUDA de otros tipos de errores si lo desea:Como
thrust::system_error
es unstd::runtime_error
, podemos manejarlo alternativamente de la misma manera que una amplia clase de errores si no requerimos la precisión del ejemplo anterior:fuente
<thrust/system/cuda_error.h>
ahora es efectiva<thrust/system/cuda/error.h>
.La forma canónica de C ++: no compruebe si hay errores ... use los enlaces de C ++ que arrojan excepciones.
Solía molestarme este problema; y solía tener una solución de función macro-cum-wrapper como en las respuestas de Talonmies y Jared, pero, ¿honestamente? Hace que usar la API CUDA Runtime sea aún más feo y similar a C.
Así que he abordado esto de una manera diferente y más fundamental. Para obtener una muestra del resultado, aquí hay parte de la
vectorAdd
muestra de CUDA , con una verificación completa de errores de cada llamada a la API de tiempo de ejecución:Una vez más, se verifican todos los posibles errores, y una excepción si se produce un error (advertencia: si el kernel causó algún error después del lanzamiento, se detectará después del intento de copiar el resultado, no antes; para asegurarse de que el kernel tuvo éxito, lo haría necesita verificar el error entre el inicio y la copia con un
cuda::outstanding_error::ensure_none()
comando).El código anterior usa mi
Thin Modern-C ++ wrappers para la biblioteca de API CUDA Runtime (Github)
Tenga en cuenta que las excepciones llevan una explicación de cadena y el código de estado de API de tiempo de ejecución CUDA después de la llamada fallida.
Algunos enlaces a cómo los errores CUDA se verifican automáticamente con estos contenedores:
fuente
La solución discutida aquí funcionó bien para mí. Esta solución utiliza funciones integradas de cuda y es muy sencilla de implementar.
El código relevante se copia a continuación:
fuente