我有以下简单的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进行计算。有人可以解释一下如何为每个块选择最佳线程数,以及如何并行实现。
答案 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 /
同时保留连续的地址访问和每个工作项的平衡工作是不可能的。