Cuda内核中的数据组织

Cuda内核中的数据组织,cuda,Cuda,我是Cuda的新手,一直在阅读教程和其他开源代码,试图理解一些东西。我知道线程层次结构的一般概念 TL;DR,我读过的所有教程都假设发送到内核的数据也是按照这个层次结构组织的,在启动内核之前没有明确这样做。在传递到内核之前,传递到内核的数据不应该在grid>block>thread层次结构中重新排列吗?下面是两个让我感到困惑的片段 我遵循了这个x+y教程。在本教程中,将显示以下代码段: _global__ void add(int n, float *x, float *y) { int i

我是Cuda的新手,一直在阅读教程和其他开源代码,试图理解一些东西。我知道线程层次结构的一般概念

TL;DR,我读过的所有教程都假设发送到内核的数据也是按照这个层次结构组织的,在启动内核之前没有明确这样做。在传递到内核之前,传递到内核的数据不应该在grid>block>thread层次结构中重新排列吗?下面是两个让我感到困惑的片段

我遵循了这个x+y教程。在本教程中,将显示以下代码段:

_global__
void add(int n, float *x, float *y)
{
  int index = blockIdx.x * blockDim.x + threadIdx.x;
  int stride = blockDim.x * gridDim.x;
  for (int i = index; i < n; i += stride)
    y[i] = x[i] + y[i];
}
上述内核按如下方式启动:

NmDistanceKernel<<<dim3(32,16,1),512>>>(batch_size, n, xyz1.data<float>(), m, xyz2.data<float>(), dist1.data<float>(), idx1.data<int>());

同样,在上面的内核中,作者假设它们传递给内核的数据是经过组织的,以便索引机制能够工作。他们没有明确地在每个线程中放置每个点,然后在块中放置一组点,在网格中放置一组云。但是,此结构假定在内核内部。

在调用内核之前,必须将数据放入GPU

数据主要以数据数组的形式传入,因此这些数组在GPU上的结构与在主机代码中的结构相同

在第一个示例中,数组x和y分别传入,因此x和y的索引都从0开始。您可以在一个大数组中传递它们,然后需要调整索引

在你的另一个例子中已经做到了。阵列xyz由所有点的x y和z值组成。顺序类似于x1 y1 z1 x2 y2 z2 x3 y3 z3。。。。这就是为什么在访问值时会看到x=[…]+0;y=[…]+1;z=[…]+2;。对于下一个点,指数都增加了3

要访问内核中的数据,需要参考CUDA提供的标识符。使用网格和块中线程的位置

在第一个示例中,程序员选择从所有线程开始读取数组中的第一个连续条目。他通过为每个线程分配一个唯一的索引来实现这一点:

int index=blockIdx.x*blockDim.x+threadIdx.x

x告诉我们线程在块中的位置,所以如果我们只启动一个块就足够了。但是,不同块中的不同线程将具有相同的索引。我们必须通过获取他们的blockIdx.x来分离他们。该块为blockDim.x长,第二个块中的第一个线程应在块1中的最后一个线程之后继续。因此,上述公式适用于索引形式

然后,每个线程向前跳转,以便第一个线程在最后一个线程刚刚读取的数据之后读取第一个数据,依此类推


启动的网格使用的尺寸越多,这些计算就越复杂。试着从简单的网格开始,如果你喜欢的话,增加复杂性。

谢谢你的回答。我知道每一个点云都是这样被展平的。我不知道在更高层次上是如何安排的。即,w.r.t网格、块和螺纹。还是Cuda会自动处理?也就是说,Grid0内的Block0内的Thread0是否总是指我传递的第一个数据元素?我在解决方案中添加了另一部分,这对您有帮助吗?在第一个示例中,x和y应分配为两个独立的连续内存区域,并且它们的长度应相等。不管实际内存地址如何,x[0]和y[0]都表示这些数组的第一个元素。
NmDistanceKernel<<<dim3(32,16,1),512>>>(batch_size, n, xyz1.data<float>(), m, xyz2.data<float>(), dist1.data<float>(), idx1.data<int>());