【问题标题】:CUDA kernels consistently returning bad resultsCUDA 内核始终返回糟糕的结果
【发布时间】:2012-07-13 06:02:53
【问题描述】:

我是一名 CUDA 初学者,已使用 CUFFT 和 CUBLAS 等 CUDA 库成功编译并运行了多个代码示例。然而,最近,我一直在尝试生成自己的简单内核,并且在调用我的内核后反复收到无意义的值。也就是说——当我将参数传递到内核中,在内核中设置它的值,然后尝试将结果复制回主机并稍后读取这些值时,它们是假的。我尝试了许多不同的简单教程内核,这些内核似乎适用于大多数在线用户,但我总是得到无意义的值。比如……

#define SIZE 10

    //  Kernel definition, see also section 4.2.3 of Nvidia Cuda Programming Guide                                      
    __global__  void vecAdd(float* A, float* B, float* C) {

      // threadIdx.x is a built-in variable  provided by CUDA at runtime                                                
      int i = threadIdx.x;
      A[i]=0;
      B[i]=i;
      C[i] = A[i] + B[i];

    }

    int main {

      int N=SIZE;
      float A[SIZE], B[SIZE], C[SIZE];
      float *devPtrA;
      float *devPtrB;
      float *devPtrC;
      int memsize= SIZE * sizeof(float);

      cudaMalloc((void**)&devPtrA, memsize);
      cudaMalloc((void**)&devPtrB, memsize);
      cudaMalloc((void**)&devPtrC, memsize);
      cudaMemcpy(devPtrA, A, memsize,  cudaMemcpyHostToDevice);
      cudaMemcpy(devPtrB, B, memsize,  cudaMemcpyHostToDevice);
      // __global__ functions are called:  Func<<< Dg, Db, Ns >>>(parameter);                                          
      vecAdd<<<1, N>>>(devPtrA,  devPtrB, devPtrC);
      cudaMemcpy(C, devPtrC, memsize,  cudaMemcpyDeviceToHost);

      for (int i=0; i<SIZE; i++)
        printf("C[%d]=%f\n",i,C[i]);

      cudaFree(devPtrA);
      cudaFree(devPtrA);
      cudaFree(devPtrA);

}

这是一个相当简单的问题;结果应该是:

C[0]=0.000000 
C[1]=1.000000 
C[2]=2.000000 
C[3]=3.000000 
C[4]=4.000000 
C[5]=5.000000 
C[6]=6.000000 
C[7]=7.000000 
C[8]=8.000000 
C[9]=9.000000 

然而,我很棒的结果总是随机的,通常看起来更像:

C[0]=nan
C[1]=-32813464158208.000000
C[2]=nan
C[3]=-27667211200843743232.000000
C[4]=34559834084263395806523272811251761152.000000
C[5]=9214363188332593152.000000
C[6]=nan
C[7]=-10371202300694685655937271382147072.000000
C[8]=121653576586393934243511643668480.000000
C[9]=-30648783863808.000000

所以基本上,当我将参数传递到 CUDA 内核并打算在其中存储结果以复制回主机时,我往往会遇到垃圾。

这个真的把我难住了。任何帮助将不胜感激。

谢谢。

【问题讨论】:

  • 您是否先在仿真模式下测试过代码?
  • 您可能应该将您对cudaMalloccudaMemcpy 的调用与CUDA_SAFE_CALL 括起来,因为目前您没有进行任何错误检查。
  • 我刚刚将 -deviceemu 参数添加到 NVCC 并收到警告,“选项 'device-emulation' 已被弃用并被忽略”。谷歌搜索表明不再支持仿真,还是我的做法不正确?
  • @nedblorf:真可惜——我已经有一段时间没有做过任何 CUDA 工作了,但仿真模式一直是一种有用的调试技术。我想我听说最新的 CUDA 工具现在包括一个调试器?您可能不得不尝试这样做。
  • 顺便说一句,只是出于好奇,你在 A 和 B 中也有垃圾吗?

标签: cuda gpu


【解决方案1】:

您应该始终检查 API 调用返回的错误。例如,C 开发人员完全习惯于从 malloc() 中检查 NULL,因为不检查 NULL 经常会导致稍后取消对空指针的引用(随之而来的是坏事)。 C++ 开发人员经常依赖异常,但许多 API 是 C 风格的(包括您正在使用的 CUDA 调用和许多其他库),因此您应该知道何时检查错误。

理想情况下,您会检查每个 API 调用的错误。就我个人而言,我不会使用 CUTIL 中的 SAFE_CALL 宏,而是检查错误,正确处理它并抛出异常 (C++) 或至少正确清理。这样,当您将实验发展为更大的应用程序时,您已经考虑过错误处理。

至少,你应该在最后检查一个错误:

cudaError_t cudaResult;
cudaResult = cudaGetLastError();
if (cudaResult != cudaSuccess)
{
    // Do whatever you want here
    // I normally create a std::string msg with a description of where I am
    // and append cudaGetErrorString(cudaResult)
}

【讨论】:

  • 非常感谢您提供此示例代码。它帮助我找到了“请求启动的资源过多”的错误。我仍在试图弄清为什么会发生这种情况。
【解决方案2】:

我运行了您的代码,没有收到任何错误。我会尝试查看 sdk 示例是否仍然运行?此外,如果您需要,GPUOcelot 还提供仿真支持(在这种情况下似乎有点矫枉过正)。

我的输出: cuda2:~/tests$ ./test C[0]=0.000000 C[1]=1.000000 C[2]=2.000000 C[3]=3.000000 C[4]=4.000000 C[5]=5.000000 C[6]=6.000000 C[7]=7.000000 C[8]=8.000000 C[9]=9.000000

【讨论】:

    【解决方案3】:

    当我没有加载内核模块时,我在使用您的代码的 Linux 主机上得到相同的行为?你确定你已经加载了驱动程序?您可以通过运行 SDK 附带的 deviceQuery 示例可执行文件来检查您是否拥有支持 CUDA 的设备。

    作为更新,如果您已加载模块(使用 lsmod 验证)。您可能需要确保 /dev/nvidia* 设备节点存在。入门指南中有一个示例脚本可助您一臂之力(第 6 页,http://developer.download.nvidia.com/compute/cuda/3_2_prod/docs/Getting_Started_Linux.pdf)。

    进一步更新,如果您按照 Tom 的建议处理错误,您会发现此错误。如果您想要一种快速而肮脏的方法,它会告诉您在哪里遇到错误,您可以查看示例书的 CUDA 代码 (http://developer.nvidia.com/object/cuda-by -example.html)。该代码提供了一个 HANDLE_ERROR,它将在您的程序遇到错误时终止您的程序,并在标准输出上提供一条消息。这不是生产代码的最佳方法,但又快又脏。

    【讨论】:

      【解决方案4】:

      我终于想通了。我在 64 位 Mac Pro 上运行,并且一直将 -Xcompiler "arch x86_64" 作为参数传递给 nvcc。 NVidia 论坛的一位版主指出,在 Mac 上,我应该将“-m64”传递给 nvcc。我一定在文档中错过了这一点。通过 -m64 修复了我的输出,并且内核现在似乎正在成功启动。感谢大家的回答。

      【讨论】:

        猜你喜欢
        • 2013-11-08
        • 1970-01-01
        • 2014-06-30
        • 2013-11-14
        • 2012-08-23
        • 2014-03-14
        • 2018-03-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多