CUDA网格跨步循环,用于嵌套for循环

问题描述

我正在使用CUDA网格跨步循环,结果看起来不错,但我不是100%理解为什么只需要对外部循环执行此跨步操作,而内部循环却没有任何变化。

__global__
void bodyForce(Body *p,float dt,int n) {
  
  int index = threadIdx.x + blockIdx.x * blockDim.x;
  int stride = blockDim.x * gridDim.x;


  for (int i = index; i < n; i += stride)
  {
    float Fx = 0.0f; float Fy = 0.0f; float Fz = 0.0f;

    for (int j = 0; j < n; j ++)
    {
      float dx = p[j].x - p[i].x;
      float dy = p[j].y - p[i].y;
      float dz = p[j].z - p[i].z;
      float distSqr = dx*dx + dy*dy + dz*dz + SOFTENING;
      float invdist = rsqrtf(distSqr);
      float invdist3 = invdist * invdist * invdist;

      Fx += dx * invdist3; Fy += dy * invdist3; Fz += dz * invdist3;
    }

    p[i].vx += dt*Fx; p[i].vy += dt*Fy; p[i].vz += dt*Fz;
  }
}

解决方法

此代码似乎直接从NVIDIA DLI入门CUDA C ++ course的评估练习中提取而来。

如果您正在学习这门课程,那么在将原始的仅CPU代码转换为GPU加速的代码的过程中,您将编写grid-stride循环。因此,代码就是您选择编写的任何代码。

外部for循环上的grid-stride循环之所以有意义的原因是,在外部for循环迭代上完成的工作是独立的。计算顺序从一个迭代到下一个迭代都无关紧要,因此可以轻松/轻松地在CUDA线程之间并行化,并且the grid-stride loop是一种分配外部for循环工作的方式(在原始跨CUDA线程的纯CPU代码。

内部for循环表示在各个迭代之间并非无关紧要的工作,因为一个迭代正在添加到上一个迭代的结果中:

while(wait(NULL) != -1);

因此,这项工作在CUDA线程之间的分配不会具有用于并行化外部for循环的相同的琐碎/机械方法。

这当然可以完成,但是这需要讲授跨线程并行缩减的概念,这一点在该课程中尚未解决。因此,明智的方法是让每个 Fx += dx * invDist3; Fy += dy * invDist3; Fz += dz * invDist3; 单独保留内部for循环,由单个线程处理。

这种认识仍然可以实现在该课程的评估练习中设定的绩效目标。