¿Cuál es la forma canónica de verificar errores utilizando la API de tiempo de ejecución CUDA?




2 Answers

La respuesta anterior de Talonmies es una buena manera de abortar una aplicación de manera asertiva.

En ocasiones, es posible que deseamos informar y recuperar una condición de error en un contexto de C ++ como parte de una aplicación más grande.

Aquí hay una manera razonablemente concisa de hacerlo lanzando una excepción de C ++ derivada de std::runtime_error usando thrust::system_error :

#include <thrust/system_error.h>
#include <thrust/system/cuda/error.h>
#include <sstream>

void throw_on_cuda_error(cudaError_t code, const char *file, int line)
{
  if(code != cudaSuccess)
  {
    std::stringstream ss;
    ss << file << "(" << line << ")";
    std::string file_and_line;
    ss >> file_and_line;
    throw thrust::system_error(code, thrust::cuda_category(), file_and_line);
  }
}

Esto incorporará el nombre de archivo, el número de línea y una descripción en idioma inglés de cudaError_t en el miembro cudaError_t .what() la excepción lanzada:

#include <iostream>

int main()
{
  try
  {
    // do something crazy
    throw_on_cuda_error(cudaSetDevice(-1), __FILE__, __LINE__);
  }
  catch(thrust::system_error &e)
  {
    std::cerr << "CUDA error after cudaSetDevice: " << e.what() << std::endl;

    // oops, recover
    cudaSetDevice(0);
  }

  return 0;
}

La salida:

$ nvcc exception.cu -run
CUDA error after cudaSetDevice: exception.cu(23): invalid device ordinal

Un cliente de some_function puede distinguir los errores de CUDA de otros tipos de errores, si lo desea:

try
{
  // call some_function which may throw something
  some_function();
}
catch(thrust::system_error &e)
{
  std::cerr << "CUDA error during some_function: " << e.what() << std::endl;
}
catch(std::bad_alloc &e)
{
  std::cerr << "Bad memory allocation during some_function: " << e.what() << std::endl;
}
catch(std::runtime_error &e)
{
  std::cerr << "Runtime error during some_function: " << e.what() << std::endl;
}
catch(...)
{
  std::cerr << "Some other kind of error during some_function" << std::endl;

  // no idea what to do, so just rethrow the exception
  throw;
}

Debido a que thrust::system_error es un std::runtime_error , alternativamente podemos manejarlo de la misma manera que una amplia clase de errores si no requerimos la precisión del ejemplo anterior:

try
{
  // call some_function which may throw something
  some_function();
}
catch(std::runtime_error &e)
{
  std::cerr << "Runtime error during some_function: " << e.what() << std::endl;
}
cuda error-checking

Mirando las respuestas y los comentarios sobre las preguntas de CUDA, y en el wiki de la etiqueta de CUDA , veo que a menudo se sugiere que el estado de retorno de cada llamada a la API debería revisarse 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 cudaGetErrorString para capturar e informar errores de manera confiable sin requerir mucho código adicional?




La solución discutida here funcionó bien para mí. Esta solución utiliza funciones de cuda integradas y es muy sencilla de implementar.

El código relevante se copia a continuación:

#include <stdio.h>
#include <stdlib.h>

__global__ void foo(int *ptr)
{
  *ptr = 7;
}

int main(void)
{
  foo<<<1,1>>>(0);

  // make the host block until the device is finished with foo
  cudaDeviceSynchronize();

  // check for error
  cudaError_t error = cudaGetLastError();
  if(error != cudaSuccess)
  {
    // print the CUDA error message and exit
    printf("CUDA error: %s\n", cudaGetErrorString(error));
    exit(-1);
  }

  return 0;
}



Related