与CUDA中的线程和块并行

时间:2018-12-12 03:27:28

标签: parallel-processing 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进行计算。有人可以解释一下如何为每个块选择最佳线程数,以及如何并行实现。

1 个答案:

答案 0 :(得分:-2)

长篇评论:

编辑: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  /

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