0

我无法理解简单 Cuda 内核中的错误。我将内核缩小到仍然显示错误的最小值。

我有一个“多边形”类,它只存储一些点。我有一个“添加一个点”的函数(只是增加计数器),我向我的多边形数组中的所有多边形添加 4 个点。最后,我调用一个使用循环更新点数的函数。如果在这个循环中我调用new_nbpts++一次,我会得到预期的答案:所有多边形都有 4 个点。如果在同一个循环中我new_nbpts++第二次调用,那么我的多边形有一个垃圾点数(4194304 个点),这是不正确的(我应该得到 8 个)。

我希望有一些我误解的东西。

完整的内核:

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


class Polygon {
public:
  __device__ Polygon():nbpts(0){};
  __device__ void addPt() {
    nbpts++;
  }; 
  __device__ void update() {
    int new_nbpts = 0;
    for (int i=0; i<nbpts; i++) {
        new_nbpts++;
        new_nbpts++;  // calling that a second time screws up my result
    }
    nbpts = new_nbpts;
  }

 int nbpts;
};


__global__ void cut_poly(Polygon* polygons, int N)
{
  int idx = blockIdx.x * blockDim.x + threadIdx.x;
  if (idx>=N) return;

  Polygon pol;
  pol.addPt();
  pol.addPt();
  pol.addPt();
  pol.addPt();

  for (int i=0; i<N; i++) {
    pol.update();
  }

  polygons[idx] = pol;
}



int main(int argc, unsigned char* argv[])
{
  const int N = 20; 
  Polygon p_h[N], *p_d;

  cudaError_t err = cudaMalloc((void **) &p_d, N * sizeof(Polygon));   

  int block_size = 4;
  int n_blocks = N/block_size + (N%block_size == 0 ? 0:1);
  cut_poly <<< n_blocks, block_size >>> (p_d, N);

  cudaMemcpy(p_h, p_d, sizeof(Polygon)*N, cudaMemcpyDeviceToHost);

  for (int i=0; i<N; i++)
   printf("%d\n", p_h[i].nbpts);

  cudaFree(p_d);

  return 0;
}
4

1 回答 1

2

你为什么在你的内核结束时这样做:

  for (int i=0; i<N; i++) {
    pol.update();
  }

?

请记住,每个线程都有自己的实例:

多边形 pol;

如果你想在内核结束时更新每个线程的 pol 实例,你只需要这样做:

pol.update();

现在,在你的情况下会发生什么?

假设您的 update() 代码只有一个:

new_nbpts++; 

在里面。

您的 0 到 N-1 的 for 循环调用 pol.update() 将在每次迭代中:

  1. 将 new_nbpts 设置为零
  2. 将 new_nbpts 总共增加 nbpts 次。
  3. 将 nbpts 的值替换为 new_nbpts

希望您可以看到这具有使 nbpts 保持不变的效果。即使在调用 pol.update() 的 for 循环的 N 次迭代之后,nbpts 的值也不会改变。

现在如果我有会发生什么:

new_nbpts++;
new_nbpts++;

在我的 update() 方法中?然后在每次调用 pol.update() 时,我将:

  1. 将 new_nbpts 设置为零
  2. 将 new_nbpts 增加两倍,总共 nbpts 次
  3. 用新的 nbpts 替换 nbpts 的值

希望您可以看到这对每次调用 pol.update()具有使 nbpts 翻倍的效果

现在,由于您在每个线程中调用 pol.update() N 次,因此您将 nbpts 的起始值加倍 N 次,即 nbpts *2^N。由于 nbpts 以 4 开头(在本例中),因此我们有 4*2^20=4194304

我不太确定你对这一切的追求是什么,但我猜你是在内核末尾运行那个 for 循环,以为你会以这种方式更新 Polygon pol 的所有不同实例。但这不是怎么做的,你只需要一个

pol.update();

在内核的末尾,如果这是您的意图。

于 2012-11-29T05:35:01.057 回答