Error Handling

Every CUDA API returns an error value of type cudaError_t except for the kernel calls. They represent different exceptions and behaviors. const char *cudaGetErrorString(cudaError_t) takes error and returns the respective error message. For example we can a good cudaDeviceSynchronize call will handle its error to like,

const cudaError_t error = cudaDeviceSynchronize();
if (error != cudaSuccess) {
 printf("code:%d, reason: %s\n", error, cudaGetErrorString(error));
 exit(1);
}

And a good CUDA program will handle errors like this in each CUDA API call. For fairly moderate size program this becomes a huge mess of extra repeated lines of code and which should be replaced with a function or a macro. Professional CUDA-C Programming Book has a very good macro to handle this situation and that is,

// Copied from Book: Professional CUDA-C Programming
#define CHECK(call)                                                            \
    {                                                                          \
        const cudaError_t error = call;                                        \
        if (error != cudaSuccess) {                                            \
            printf("Error: %s:%d, ", __FILE__, __LINE__);                      \
            printf("code:%d, reason: %s\n", error, cudaGetErrorString(error)); \
            exit(1);                                                           \
        }                                                                      \
    }

and the error checking code becomes,

CHECK(cudaDeviceSynchronize());

See Qazalbash/CUDAForge/code/1_ArrSum/ArrSum.cu for complete code example.