在 Cuda 中简单地添加两个 int,结果总是相同的

Posted

技术标签:

【中文标题】在 Cuda 中简单地添加两个 int,结果总是相同的【英文标题】:Simple adding of two int's in Cuda, result always the same 【发布时间】:2012-05-18 10:31:03 【问题描述】:

我开始了学习 Cuda 的旅程。我正在使用一些 hello world 类型的 cuda 代码,但它不起作用,我不知道为什么。

代码非常简单,取两个整数并将它们添加到 GPU 上并返回结果,但无论我将数字更改为什么,我都会得到相同的结果(如果数学以这种方式工作,我会做得更好主题比我实际做的)。

示例代码如下:

// CUDA-C includes
#include <cuda.h>
#include <stdio.h>

__global__ void add( int a, int b, int *c ) 
    *c = a + b;


extern "C"
void runCudaPart();

// Main cuda function

void runCudaPart() 

    int c;
    int *dev_c;

    cudaMalloc( (void**)&dev_c, sizeof(int) );
    add<<<1,1>>>( 1, 4, dev_c );

    cudaMemcpy( &c, dev_c, sizeof(int), cudaMemcpyDeviceToHost );

    printf( "1 + 4 = %d\n", c );
    cudaFree( dev_c );


输出似乎有点不对劲:1 + 4 = -1065287167

我正在设置我的环境,只是想知道代码是否有问题,否则可能是我的环境。

更新:我尝试添加一些代码来显示错误,但我没有得到输出,但数字发生了变化(它是输出错误代码而不是答案吗?即使我没有在内核其他方面做任何工作比分配一个变量我仍然得到类似的结果)。

// CUDA-C includes
#include <cuda.h>
#include <stdio.h>

__global__ void add( int a, int b, int *c ) 
    //*c = a + b;
    *c = 5;


extern "C"
void runCudaPart();

// Main cuda function

void runCudaPart() 

    int c;
    int *dev_c;

    cudaError_t err = cudaMalloc( (void**)&dev_c, sizeof(int) );
    if(err != cudaSuccess)
         printf("The error is %s", cudaGetErrorString(err));
    
    add<<<1,1>>>( 1, 4, dev_c );

    cudaError_t err2 = cudaMemcpy( &c, dev_c, sizeof(int), cudaMemcpyDeviceToHost );
    if(err2 != cudaSuccess)
         printf("The error is %s", cudaGetErrorString(err));
    


    printf( "1 + 4 = %d\n", c );
    cudaFree( dev_c );


代码看起来不错,可能与我的设置有关。在 OSX lion 上安装 Cuda 是一场噩梦,但我认为它可以工作,因为 SDK 中的示例似乎很好。到目前为止,我采取的步骤是访问 Nvida 网站并下载驱动程序、工具包和 SDK 的最新 mac 版本。然后我添加了export DYLD_LIBRARY_PATH=/usr/local/cuda/lib:$DYLD_LIBRARY_PATH 和 'PATH=/usr/local/cuda/bin:$PATH` 我做了一个 deviceQuery 并传递了以下关于我的系统的信息:

[deviceQuery] starting...

/Developer/GPU Computing/C/bin/darwin/release/deviceQuery Starting...

 CUDA Device Query (Runtime API) version (CUDART static linking)

Found 1 CUDA Capable device(s)

Device 0: "GeForce 320M"
  CUDA Driver Version / Runtime Version          4.2 / 4.2
  CUDA Capability Major/Minor version number:    1.2
  Total amount of global memory:                 253 MBytes (265027584 bytes)
  ( 6) Multiprocessors x (  8) CUDA Cores/MP:    48 CUDA Cores
  GPU Clock rate:                                950 MHz (0.95 GHz)
  Memory Clock rate:                             1064 Mhz
  Memory Bus Width:                              128-bit
  Max Texture Dimension Size (x,y,z)             1D=(8192), 2D=(65536,32768), 3D=(2048,2048,2048)
  Max Layered Texture Size (dim) x layers        1D=(8192) x 512, 2D=(8192,8192) x 512
  Total amount of constant memory:               65536 bytes
  Total amount of shared memory per block:       16384 bytes
  Total number of registers available per block: 16384
  Warp size:                                     32
  Maximum number of threads per multiprocessor:  1024
  Maximum number of threads per block:           512
  Maximum sizes of each dimension of a block:    512 x 512 x 64
  Maximum sizes of each dimension of a grid:     65535 x 65535 x 1
  Maximum memory pitch:                          2147483647 bytes
  Texture alignment:                             256 bytes
  Concurrent copy and execution:                 Yes with 1 copy engine(s)
  Run time limit on kernels:                     Yes
  Integrated GPU sharing Host Memory:            Yes
  Support host page-locked memory mapping:       Yes
  Concurrent kernel execution:                   No
  Alignment requirement for Surfaces:            Yes
  Device has ECC support enabled:                No
  Device is using TCC driver mode:               No
  Device supports Unified Addressing (UVA):      No
  Device PCI Bus ID / PCI location ID:           4 / 0
  Compute Mode:
     < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >

deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 4.2, CUDA Runtime Version = 4.2, NumDevs = 1, Device = GeForce 320M
[deviceQuery] test results...
PASSED

更新:真正奇怪的是,即使我删除了内核中的所有工作,我仍然得到 c 的结果?我已经重新安装了 cuda 并在示例中使用了 make 并且所有示例都通过了。

【问题讨论】:

对于初学者来说,cudaMalloc 和 cudaMemcpy 都返回结果代码。打印任何不是 cudaSuccess 的内容可能具有教育意义。 @HenkHolterman 不走运..我对 Cuda 很陌生,所以我可能完全错了,但如果出现错误并且没有关于错误的消息但数字已更改,我会尝试创建输出(即使我在内核中输入了一个特定的数字,它也不会返回。)我更新了代码,似乎内核甚至没有被使用。 我不得不做一个微小的改变。删除 extern "C" 以使其链接。 是的。所以我上面发布的代码是从 C 程序调用的。 C 程序有一个 main 并且只调用 runCudaPart();它应该运行。我重新安装了 cuda 工具包、驱动程序、sdk ..然后看到你的帖子并将代码复制并粘贴回文件中,按照你所做的方式更改它(注释掉 C 部分),添加一个 main 并通过 nvcc 运行它。有效。然后我从 C 代码再次运行它并且它工作。在我单独运行它或使用 C 代码运行它之前,它给了我错误的数字。 根据您上一个问题的 .pro 文件配置,将您的设备架构调整为 CUDA_ARCH = sm_13(不是 sm_20),因为您拥有计算能力为 1.3 的设备 【参考方案1】:

这里基本上有两个问题:

    您没有为正确的架构编译内核(从 cmets 收集) 您的代码包含不完善的错误检查,它错过了发生运行时错误的点,导致出现神秘和无法解释的症状。

在运行时 API 中,大多数与上下文相关的操作都是“惰性”执行的。当您第一次启动内核时,运行时 API 将调用代码以智能地从工具链为目标硬件发出的胖二进制图像中找到合适的 CUBIN 图像并将其加载到上下文中。这还可以包括 PTX 的 JIT 重新编译以实现向后兼容的架构,但不能反过来。因此,如果您为计算能力 1.2 设备编译了内核并在计算能力 2.0 设备上运行它,则驱动程序可以 JIT 编译它包含的新架构的 PTX 1.x 代码。但反过来是行不通的。因此,在您的示例中,运行时 API 将生成错误,因为它无法在嵌入在可执行文件中的 CUDA fatbinary 映像中找到可用的二进制映像。错误消息非常神秘,但您会收到错误消息(请参阅this question 了解更多信息)。

如果您的代码包含这样的错误检查:

cudaError_t err = cudaMalloc( (void**)&dev_c, sizeof(int) );
if(err != cudaSuccess)
     printf("The error is %s", cudaGetErrorString(err));


add<<<1,1>>>( 1, 4, dev_c );
if (cudaPeekAtLastError() != cudaSuccess) 
    printf("The error is %s", cudaGetErrorString(cudaGetLastError()));


cudaError_t err2 = cudaMemcpy( &c, dev_c, sizeof(int), cudaMemcpyDeviceToHost );
if(err2 != cudaSuccess)
     printf("The error is %s", cudaGetErrorString(err));

内核启动后的额外错误检查应捕获内核加载/启动失败产生的运行时 API 错误。

【讨论】:

这可能是初学者的最佳实践。在学习时检查每个步骤是否有错误。您应该会收到有关设备架构的错误。 这也是专业人士的最佳实践 :) 绝对适用于调试版本,但我也会将检查留在发布版本中。如果在发布版本中不需要检查,请使用预处理器将它们替换为存根。【参考方案2】:
#include <stdio.h>
#include <conio.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <device_launch_parameters.h>


__global__ void Addition(int *a,int *b,int *c)


   *c = *a + *b;

int main()

  int a,b,c;
  int *dev_a,*dev_b,*dev_c;
  int size = sizeof(int);

  cudaMalloc((void**)&dev_a, size);
  cudaMalloc((void**)&dev_b, size);
  cudaMalloc((void**)&dev_c, size);

  a=5,b=6;

  cudaMemcpy(dev_a, &a,sizeof(int), cudaMemcpyHostToDevice);  
  cudaMemcpy(dev_b, &b,sizeof(int), cudaMemcpyHostToDevice);  

  Addition<<< 1,1 >>>(dev_a,dev_b,dev_c);
  cudaMemcpy(&c, dev_c,size, cudaMemcpyDeviceToHost);

   cudaFree(&dev_a);
   cudaFree(&dev_b);
   cudaFree(&dev_c);

   printf("%d\n", c);
   getch();
   return 0;

【讨论】:

以上是关于在 Cuda 中简单地添加两个 int,结果总是相同的的主要内容,如果未能解决你的问题,请参考以下文章

使用 CUDA 进行大整数加法

在我的机器上操作大向量时,CUDA 推力很慢

Karatsuba - 多项式乘法与 CUDA

如何在cuda中的不同gpu之间复制内存

CUDA 内核是如何启动的?

简单直接的CUDA改造