【问题标题】:Parallelize four and more nested loops with CUDA使用 CUDA 并行化四个或更多嵌套循环
【发布时间】:2016-10-09 01:15:23
【问题描述】:

我正在研究生成并行 C++ 代码的编译器。我是 CUDA 编程新手,但我正在尝试将 C++ 代码与 CUDA 并行化。

目前,如果我有以下顺序 C++ 代码:

for(int i = 0; i < a; i++) {
    for(int j = 0; j < b; j++) {
        for(int k = 0; k < c; k++) {
            A[i*y*z + j*z + k*z +l] = 1;
        }
    }
}

这会产生以下 CUDA 代码:

__global__ void kernelExample() {
    int _cu_x = ((blockIdx.x*blockDim.x)+threadIdx.x);
    int _cu_y = ((blockIdx.y*blockDim.y)+threadIdx.y);
    int _cu_z = ((blockIdx.z*blockDim.z)+threadIdx.z);

    A[_cu_x*y*z + _cu_y*z + _cu_z] = 1;
}

所以每个循环嵌套都映射到一个维度,但是并行化四个或更多嵌套循环的正确方法是:

for(int i = 0; i < a; i++) {
    for(int j = 0; j < b; j++) {
        for(int k = 0; k < c; k++) {
            for(int l = 0; l < d; l++) {
                A[i*x*y*z + j*y*z + k*z +l] = 1;
            }
        }
    }
}

有没有类似的方法?值得注意的是:所有循环维度都是并行的,迭代之间没有依赖关系。

提前致谢!

编辑:目标是将所有迭代映射到 CUDA 线程,因为所有迭代都是独立的并且可以同时执行。

【问题讨论】:

  • 对于 N 个嵌套循环,您使用 N 个维度。您不必拘泥于 CUDA 提供的 3 个维度,只需计算您自己的索引即可。
  • 能否为我的示例提供一个包含四个嵌套循环的解决方案?
  • 解决方案很简单,但是这个文本输入字段太小了。
  • 也许你写一个答案?还是这太努力了?将不胜感激!

标签: c++ loops parallel-processing cuda


【解决方案1】:

你可以保持外循环不变。此外,最好使用.x 作为最内层循环,这样您就可以使用access the global memory efficiently

__global__ void kernelExample() {
    int _cu_x = ((blockIdx.x*blockDim.x)+threadIdx.x);
    int _cu_y = ((blockIdx.y*blockDim.y)+threadIdx.y);
    int _cu_z = ((blockIdx.z*blockDim.z)+threadIdx.z);
    for(int i = 0; i < a; i++) {
        A[i*x*y*z + _cu_z*y*z + _cu_y*z + _cu_x] = 1;
    }
}

但是,如果您的a,b,c,d 都非常小,您可能无法获得足够的并行度。在这种情况下,您可以将线性索引转换为 n 维索引。

__global__ void kernelExample() {
    int tid = ((blockIdx.x*blockDim.x)+threadIdx.x);
    int i = tid / (b*c*d);
    int j = tid / (c*d) % b;
    int k = tid / d % c;
    int l = tid % d;

    A[i*x*y*z + j*y*z + k*z + l] = 1;
}

但请注意,计算 i,j,k,l 可能会引入大量开销,因为整数除法和 mod 在 GPU 上的速度很慢。作为替代方案,您可以将i,j 映射到.z.y,并以类似的方式仅计算k,l.x 的更多维度。

【讨论】:

  • 感谢您的回答,但我不想在我的内核中有任何循环,因为所有迭代都是独立的并且可以同时执行。
  • @siebenschlaefer 有了足够大的 blockDim 和 gridDim,您可能已经获得了足够的并行度。保持循环就好了。
  • 确实如此,但在我测试的所有源程序中并非如此。
  • 事实上,在某些情况下保持循环可能会增加每个线程的工作量,与只为每个线程提供少量工作量相比,这可以提高性能。实际上,您可以通过增加每个线程的工作量而不是使用更多线程来公开更多可用并行性。
  • 如果所有循环迭代都是独立的,那么您可以展平或“折叠”循环。这个概念并不是 cuda 独有的。它可以在普通的 C/C++ 代码中完成。如果您想在每个线程中进行一次循环迭代,请在主机代码中折叠循环并为您的内核执行转换为网格。
猜你喜欢
  • 2018-09-30
  • 2017-06-20
  • 1970-01-01
  • 1970-01-01
  • 2014-07-05
  • 1970-01-01
  • 1970-01-01
  • 2015-11-18
相关资源
最近更新 更多