CUDA:线程可以创建所有数据的单独副本吗?

时间:2013-04-18 23:48:40

标签: memory-management cuda thread-synchronization

我有一个非常基本的问题,我在浏览文件后无法理解。我执行我的一个项目时遇到这个问题,因为我得到的输出完全损坏,我相信问题是内存分配或线程同步。 好的问题是: 每个线程都可以创建传递给内核函数的所有变量和指针的单独副本吗?或者它只是创建变量的副本,但是我们传递的指针是在所有线程中共享的内存。 e.g。

int main()
{
  const int DC4_SIZE = 3;
  const int DC4_BYTES = DC4_SIZE * sizeof(float);
  float * dDC4_in;
  float * dDC4_out;
  float hDC4_out[DC4_SIZE];
  float hDC4_out[DC4_SIZE];

  gpuErrchk(cudaMalloc((void**) &dDC4_in, DC4_BYTES));
  gpuErrchk(cudaMalloc((void**) &dDC4_out, DC4_BYTES));
  // dc4 initialization function on host which allocates some values to DC4[] array

  gpuErrchk(cudaMemcpy(dDC4_in, hDC4_in, DC4_BYTES, cudaMemcpyHostToDevice));
  mykernel<<<10,128>>>(VolDepth,dDC4_in);
  cudaMemcpy(hDC4_out, dDC4_out, DC4_BYTES, cudaMemcpyDeviceToHost);
}

__global__ void mykernel(float VolDepth,float * dDC4_in,float * dDC4_out)
{
    for(int index =0 to end)
      dDC4_out[index]=dDC4_in[index] * VolDepth;
}

所以我将dDC4_in和dDC4_out指针传递给GPU,dDC4_in用一些值初始化并计算dDC4_out并复制回主机, 那么我的所有1280个线程都有单独的dDC4_in / out副本,或者它们都将在GPU上的同一副本上工作,覆盖其他线程的值?

1 个答案:

答案 0 :(得分:3)

全局内存由网格中的所有线程共享。传递给内核的参数(使用cudaMalloc分配的参数)位于全局内存空间中。

线程确实有自己的内存(本地内存),但在您的示例中,dDC4_indDC4_out由所有线程共享。

作为一般性的破败(取自the CUDA Best Practices文档):

enter image description here

在DRAM方面: 本地内存(和寄存器)是每线程,共享内存是每块,全局,常量和纹理是每个网格。

此外,可以在主机上读取和修改全局/常量/纹理内存,而本地和共享内存仅在内核持续时间内使用。也就是说,如果您在本地或共享内存中有一些重要信息并且内核完成,则会回收该内存并丢失您的信息。此外,这意味着从主机获取数据到内核的唯一方法是通过全局/常量/纹理内存。

无论如何,在您的情况下,建议如何修复代码有点困难,因为您根本不考虑线程。不仅如此,在您发布的代码中,您只向您的内核传递了2个参数(需要3个参数),因此您的结果有点缺乏也就不足为奇了。即使你的代码是有效的,你也会让每个线程从0循环到end并将其写入内存中的相同位置(这将被序列化,但你不知道哪个写入是最后一个经过)。除了竞争条件之外,你还有每个线程做同样的计算;您的每个1280个线程将执行for循环并执行相同的步骤。您必须决定线程到数据元素的映射,根据线程到元素映射将内核中的工作分开,然后根据它执行计算。

e.g。如果您有1个线程:1个元素映射,

__global__ void mykernel(float VolDepth,float * dDC4_in,float * dDC4_out)
{
    int index = threadIdx.x + blockIdx.x*blockDim.x;
    dDC4_out[index]=dDC4_in[index] * VolDepth;
}

当然,这也需要更改内核启动配置以获得正确数量的线程,如果线程和元素不是精确的倍数,则需要在内核中添加一些边界检查。