首页 > 解决方案 > 与 CUDA 中的线程和块并行化

问题描述

我有以下简单的嵌套 for 循环

float a[1024][1024], b[1024]

for(i=1; i < 1024; i++){
    for(j = 1; j < 1024 - i; j++){
        b[i + j] += a[i][j];    
    }
}

而且我正在尝试了解如何使用 CUDA 线程和线程块来划分这个问题以与 GPU 并行化。到目前为止,我相信我总共进行了 N = 522753 次计算。我不完全确定如何从这里开始:我知道每个块中的线程数应该是 32 的倍数。例如,如果每个块的线程数是 1024,那么我至少需要 511 个块,其中每个线程从 1 -> N 进行计算。有人可以解释如何选择每个块的最佳线程数,以及如何实际并行实现。

标签: parallel-processingcuda

解决方案


长评:

编辑:c 矩阵应该是列主要而不是行主要,并且排序应该在列而不是行上,但为了便于阅读,我将其保留为行主要。

您可以(一次)为每个工作项准备一个计数和引用矩阵,以便第一列是计数,其余是引用,最后一列是写入地址

c[0] = {1, &a[1][1],                   &b[2]}; // b[2]
c[1] = {2, &a[1][2],&a[2][1],          &b[3]}; // b[3]
c[2] = {3, &a[1][3],&a[2][2],&a[3][1], &b[4]}; // b[4]
..

然后根据它们的索引数量/子数组大小对它们进行排序(一次),使它们成为

   c[0]    = {1, &a[1][1],         &b[2]}    //  b[2]
   c[1]    = {1, &a[1022][1],      &b[1023]} // b[1023]
   ..
   c[k]    = {5, x1,y1,z1,t1,w1,   &b[m]} // b[m]
   c[k+1]  = {5, x2,y2,z2,t2,w2,   &b[n]} // b[n]

平衡经线/块的 cuda 线程之间的工作量。

然后访问 c 矩阵(每行 1 个 cuda 线程)以了解在每个工作项的普通 for 循环中要添加哪些元素。

   const int length = (int)c[workitemId][0];
   for(int i=1;i<length+1;i++)
      resultOfWorkitem += *(c[workitemId][i]);
   *(c[workitemId][length+1])=resultOfWorkitem;

由于所有排序列表只会排序一次,如果您要经常进行计算部分,那么这个额外的引用部分可能比使用原子更快,并且可能会被缓存以供 c 和数组的只读访问。

如果随机写入地址成为性能问题,您可以根据最后一项的地址(连续的 b 索引)对 c 数组进行排序,但这会降低相邻 cuda 线程之间的工作平衡。也许这更快,没有测试。也许对 a 的第二个索引值排序 c 可以通过减少读取次数来加快速度,尤其是当您对它们之间的每一行元素进行排序时,它们会与相邻线程的读取连续,类似于第一部分

 c[0] = {1, &a[1][1] // address x    \
 c[1] = {2, &a[1][2] // address x+1   > less than L1 cache line size 128byte?
 c[2] = {3, &a[1][3] // address x+2  /

保持每个工作项的连续地址访问和平衡工作是不可能的。


推荐阅读