【问题标题】:Cuda returns wrong value from __device__ function when cos is used使用 cos 时,Cuda 从 __device__ 函数返回错误值
【发布时间】:2015-03-15 17:59:41
【问题描述】:

我正在尝试在 nvidia GPU 上运行此代码,但它返回奇怪的值。它由 main.cuexmodul.cu 两个模块组成(在下面列出)。对于我正在使用的建筑:

nvcc -dc -arch sm_35 main.cu
nvcc -dc -arch sm_35 exmodul.cu
nvcc     -arch sm_35 -lcudart -o main main.o exmodul.o

如果我运行它,我会得到奇怪的最后一行!!! gd 必须为 1

result=0
result=0
result=0
result=0
gd=-0.5
  • 当我将exmodul.cu 中的1.0 更改为大于 1.000000953 或下面0.999999999999999945,它返回正确 结果。
  • 当我在exmodul.cu 中更改1.1 时,除了值1.0 之外,它也会失败。
  • 行为不依赖于同一模块中的常量2.0
  • 当我使用另一个函数而不是 cos(如 sinexp)时,它可以正常工作。
  • 使用double q = cos(1.1); 无效。
  • 当我将函数 extFunc() 复制到模块 main.cu 时,它可以正常工作。
  • 如果我在main.cu 中取消注释*gd=1.0;,它会返回正确的1.0

在 Nvidia GT750M 和 GeForce GTX TITAN Black 上测试。 (在 GT750M 上返回不同的值 gd=6.1232329394368592e-17 但仍然错误)。操作系统:Debian Jessie。

$ nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2013 NVIDIA Corporation
Built on Thu_Mar_13_11:58:58_PDT_2014
Cuda compilation tools, release 6.0, V6.0.1

你知道出了什么问题吗?

谢谢,卢卡斯


main.cu

#include <stdio.h>   // printf
#include "exmodul.h" // extFunc

__global__ void mykernel(double*gd);
void deviceCheck();

int main(int argc, char *argv[])
{
    double gd, *d_gd;
    cudaMalloc(&d_gd, sizeof(double)); deviceCheck();
    mykernel<<<1,1>>>(d_gd);           deviceCheck();
    cudaMemcpy(&gd, d_gd, sizeof(double), cudaMemcpyDeviceToHost);
                                       deviceCheck();
    cudaFree(d_gd);                    deviceCheck();
    fprintf(stderr,"gd=%.17g\n",gd);
    return 0;
}

void deviceCheck()
{
    cudaError_t result = cudaSuccess;
    cudaDeviceSynchronize();
    result = cudaGetLastError();
    fprintf(stderr,"result=%d\n",result); fflush(stderr);
}

__global__ void mykernel(double *gd)
{
    *gd = extFunc();
    //*gd=1.0;
    __syncthreads();
    return;
}

exmodul.cu

#include "exmodul.h"

__device__ double extFunc()
{
    double q = 1.1;
    q = cos(q);
    if(q<2.0) { q = 1.0; }
    return q;
}

exmodul.h

__device__ double extFunc();

【问题讨论】:

  • cos() 的返回值范围是 -1 ... +1。所以这一行:'if(q
  • 这一行:'printf(stderr,"gd=%.17g\n",gd);'不正确,应该是:'fprintf(stderr,"gd=%.17g\n",gd);' // 注意不同的函数调用 另外,'gd' 中的值始终为 1.0,格式转换没有小数点左侧的字符来打印 1。这就是为什么所有打印值都是 0
  • user3629249:谢谢。不需要包含math.h,请参阅[1]。我希望它必须返回 q==1 因为-1 &lt; cos &lt;+1,但它不起作用。而且我不知道为什么..fprintf 是我在将代码复制到这里时犯的错误。 [1]devtalk.nvidia.com/default/topic/792656/…
  • 我无法重现该问题,但我在 Windows 上使用 CUDA 6.5。不同 GPU 上返回的不同值表明 CUDA API 调用失败。您的错误检查似乎没有尽可能严格,您可能想尝试直接检查 API 函数的返回状态,一个启动前和启动后的内核错误,如图所示,例如,here
  • @Luuuucky 根据 NVIDIA 的说法,Debian 是 CUDA 6.0 支持的操作系统吗?如果没有,你就靠你自己了,因为 NVIDIA 尚未验证操作系统的正确 CUDA 操作。您可能想咨询 Debian 特定的论坛或邮件列表。我怀疑问题是您系统的本地问题(安装错误等)。

标签: c memory-management cuda nvidia trigonometry


【解决方案1】:

我能够在受支持的配置(CUDA 6.5、CentOS 6.2、K40)上重现有问题的行为。

当我从 CUDA 6.5 切换到 CUDA 7 RC 时,问题就消失了。

在旧配置(CUDA 5.5、CentOS 6.2、M2070)上似乎也无法重现该问题

我建议切换到 CUDA 7 RC 来解决这个问题。我怀疑编译过程中存在一个已经修复的潜在错误。

【讨论】:

  • 谢谢。我把它作为一个错误提交了,没有 nvidia。
猜你喜欢
  • 2023-03-22
  • 1970-01-01
  • 2011-08-08
  • 2011-07-14
  • 2014-07-17
  • 2020-01-31
  • 1970-01-01
  • 2011-12-25
  • 2023-03-08
相关资源
最近更新 更多