请教大家,我的程序里面有一个多层循环,相当费时间,大概的形式入下
[indent]
double sumcosttemp = 0;
double averagetx = 0;
for(int i=0;i<24;++i)
{
for(int j=0;j<850;++j)
{
for(int m=0;m<3;++m)
{
averagetx = 0;
for(int n=0;n<3;++n)
{
sumcosttemp = 0;
for(int kk=0;kk<199;++kk)
{
sumcosttemp += a[kk] * (*(S+(long)(tv[n]-1)*3 + kk*53490*3 + m));
}
tx[i][j][m][n]= *(Meanface+(tv[n]-1)*3+m) + sumcosttemp;
averagetx += tx[i][j][m][n];
}
cx[i][j][m] = averagetx/3;
}
}
}
其中,a[kk] ,*S,tx,CX,都是传入到设别上的全局变量,请问一下 这个优化有什么比较好的思路吗????
[/indent]
LZ您好:
拆分循环一般是看相关性和依赖性,以确定拆分后的执行逻辑和拆分前一致。
在有多个循环可供拆分的时候,往往会有所取舍,并不需要拆分全部的循环,可能只需要拆分部分循环即可满足并行性要求。
具体到您的算法,i,j两层循环目测是某种空间位置的坐标的循环,每个点是独立的,所以这两层循环是可拆的。
m,n两层循环似乎是局部的某种处理或者模板一类的东西,最内层的kk循环似乎是某种查表的具体算法。
这三层循环内的结果的保存多为累加。
其中如果单考虑kk循环或者kk循环和n循环,那么可以使用并行规约来快速计算。但是现在通盘考虑,您外层的i,j循环循环次数也足够多,那么内层的3个循环也可以不用拆分,让一个线程完成一套即可。
此时需要适当优化下访存
从您的代码中看,a[kk]这个数组是不变的,也是每次最内部的循环都访问的,考虑到我们让每个线程都会执行这个循环,以及a会多次读取到,可以考虑将a缓冲到shared memory中。
tv[3]这个小型的数组也可以缓存到局部。
tx数组从您的代码中看仅仅起到了保存临时数据的作用,其每个值都累加给了averagetx变量,那么如果tx数组的内容在您的算法的其他地方(本处没有展示的地方)并无使用的话,这里完全可以换成一个临时变量记录每次kk循环的结果,并累加给averagetx,或者直接将tx右侧的计算式累加给averagetx。
cx直接使用的话,会有不算太严重的合并访问问题,但是考虑到您的计算强度,这个访存问题可能不是瓶颈,如果需要进一步合并访问,也可以将cx临时缓冲到shared memory,然后block内的线程合作写入。
这样一来,您一共需要启动24*850=20400个线程,假定是8 SMX的GPU,每个SMX上有超过2400个线程,这个数量一般来说是够用了。如果您觉得线程数有些少,还可以把m循环也拆开。
以及将内部三层循环留给线程搞定,在您i,j规模扩大时,无需修改实现,仅仅扩大启动的线程规模即可。
大致如此,以上分析供您参考,实现方法不唯一。
祝您编码顺利~
谢谢版主的回答,我现在采用81024个线程的方法,
其中sumcosttemp += a[kk] * ((S+(long)(tv[n]-1)3 + kk534903 + m))计算是一个199的循环, a[kk]是一个126224的double数组,其实我的tv也是由一个很大的数组中获得的,采用现在8*1024的方法,速度还是很纠结,我想把内层的199的循环也并行,不知道效果能不能好点,这样的话,好像需要太多的线程了吧?
LZ您好:
1:从您给出的代码中并无法看出您的a[kk]是如此大的数组,如果您的循环中仅仅使用该数组的一个局部的话,请您将该局部部分缓冲到shared memory然后反复使用即可。tv同理。
2:单一增加线程数量并不能凭空增加效能的,线程数量足够多即可,并不需要非常非常多。
3:无法仅从您的线程开辟情况评估您的实现好坏以及能否进一步改进。您可以尝试各种不同的方法,并加以比较和改进。
大致如此,祝您好运~