7

我不认为我是 Cuda 的新手,但显然我是。

我最近将我的 cuda 设备升级到了一个功能强大的 1.3 到 2.1 (Geforce GT 630)。我也想对 Cuda 工具包 5.0 进行全面升级。

我可以编译一般的 cuda 内核,但 printf 即使设置了 -arch=sm_20 也无法工作。

代码:

#include <stdio.h>
#include <assert.h>
#include <cuda.h>
#include <cuda_runtime.h>

__global__ void test(){

    printf("Hi Cuda World");
}

int main( int argc, char** argv )
{

    test<<<1,1>>>();
        return 0;
}

编译器:

Error   2   error MSB3721: The command ""C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\bin\nvcc.exe" -gencode=arch=compute_10,code=\"sm_20,compute_10\" --use-local-env --cl-version 2010 -ccbin "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin"  -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\include" -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\include"  -G   --keep-dir "Debug" -maxrregcount=0  --machine 32 --compile -arch=sm_20  -g   -D_MBCS -Xcompiler "/EHsc /W3 /nologo /Od /Zi /RTC1 /MDd  " -o "Debug\main.cu.obj" "d:\userstore\documents\visual studio 2010\Projects\testCuda\testCuda\main.cu"" exited with code 2.  C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\BuildCustomizations\CUDA 5.0.targets  592 10  testCuda
Error   1   error : calling a __host__ function("printf") from a __global__ function("test") is not allowed d:\userstore\documents\visual studio 2010\Projects\testCuda\testCuda\main.cu    9   1   testCuda

由于这个问题,我的生活即将结束……完成了。请从屋顶上告诉我答案。

4

3 回答 3

28

如果你printf在内核中使用,你应该使用cudaDeviceSynchronize()

#include <stdio.h>
#include <assert.h>
#include <cuda.h>
#include <cuda_runtime.h>

__global__ void test(){
    printf("Hi Cuda World");
}

int main( int argc, char** argv )
{
    test<<<1,1>>>();
    cudaDeviceSynchronize();
    return 0;
}
于 2013-03-28T10:40:32.530 回答
11

在内核中 printf 仅在计算能力 2 或更高的硬件中受支持。因为您的项目设置为同时构建计算能力 1.0 和计算能力 2.1,所以 nvcc 会多次编译代码并构建多架构 fatbinary 对象。错误是在计算能力 1.0 编译周期生成的,因为该架构printf不支持调用。

如果从项目中删除计算能力 1.0 构建目标,错误将消失。

您也可以像这样编写内核:

__global__ void test()
{
#if __CUDA_ARCH__ >= 200
    printf("Hi Cuda World");
#endif
}

在为计算能力 2.0 或高目标构建时,该__CUDA_ARCH__符号只会 >= 200,这将允许您为计算能力 1.x 设备编译此代码而不会遇到语法错误。

当为正确的架构编译并且没有输出时,您还需要确保内核完成并且驱动程序刷新输出缓冲区。为此,在主机代码中内核启动后添加一个同步调用

例如:

int main( int argc, char** argv )
{

    test<<<1,1>>>();
    cudaDeviceSynchronize();
    return 0;
}

[免责声明:所有代码在浏览器中编写,从未编译,使用风险自负]

如果你同时做这两件事,你应该能够编译、运行并查看输出。

于 2013-03-28T06:45:10.290 回答
2

只需使用cudaDeviceSynchronize(). 作为@Tomasz 答案的补充。

具有 2.x 或更高计算能力的设备支持从 CUDA 内核中调用 printf。

printf输出存储在一个固定大小的循环缓冲区中并且此缓冲区仅被刷新用于:

  • 内核启动的开始
  • 同步(例如 cudaDeviceSynchronize())
  • 阻塞内存副本(例如 cudaMemcpy(...))
  • 模块加载/卸载
  • 上下文破坏

所以最简单的“Hello world”示例:

#include <stdio.h>

__global__ void hello() {
    printf("Hello from GPU);
}

int main() {
    hello<<<1, 1>>>();
    cudaDeviceSynchronize();
}

参考:

于 2020-04-10T19:18:25.973 回答