为什么编译器无法检测到在设备上调用了主机函数,如何解决?

Why the compiler can't detect that a host function is called on the device, and how to fix it?

请看这段代码:

void bar() {}

__host__ __device__ void foo()
{
  bar();
}

__global__ void kernel()
{
  foo();
}

int main()
{
  kernel<<<1, 1>>>();
  gpuErrchk(cudaPeekAtLastError());

  gpuErrchk(cudaDeviceSynchronize());

  return 0;
}

我花了几个小时试图解决 an illegal memory access was encountered 运行时错误。事实证明,原因是 bar() 函数——它没有声明为 __device__。但!但是代码可以编译!它会产生警告,但会编译!警告说:

warning: calling a __host__ function("bar") from a __host__ __device__
function("Test::foo") is not allowed

由于我的项目的编译产生了很多输出,所以我根本没有看到那个警告。但是如果我从 foo() 函数中删除 __device__ 属性,我会得到预期的错误:

error: identifier "foo" is undefined in device code

问题是为什么编译器只打印 warning 以及如何将它变成 error?

The question is why the compiler prints only a warning and how to turn it into an error?

编译器只打印一条警告,因为它不知道(在编译调用函数时)该函数是否会在运行时以令人反感的配置(即在设备代码上或从设备代码中)实际调用.

and how to turn it into an error?

nvcc manual 您可以添加:

-Werror all-warnings

将所有警告标记为错误

-Werror cross-execution-space-call

仅将此类警告标记为错误。

另见 here。对于那些会问为什么我没有标记为受骗者的人,另一个问题不包括关于编译器为何以这种方式运行的问题(或答案本身)。

I spent hours trying to solve the... error. ... But the code compiles! It produces a warning, but compiles!

您需要重新审视您的调试方法:-(

任何您尚未积极证明 给您自己的警告都是无关紧要的 - 是您需要查找错误的地方。解决警告比证明它们无效要容易得多,也更有回报。 (通过解决,我的意思是解决潜在的条件,而不是抑制警告,或者 const_cast'ing 等)

所以,不要用编译器将警告变成错误,而是将它们变成essentially-errors 在你的脑海中。干净,warning-free代码=快乐生活。