问题描述
我正在使用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循环,由单个线程处理。
这种认识仍然可以实现在该课程的评估练习中设定的绩效目标。