科学计算,需要对一个二维数组做数值微分。
每个点的数值微分,需要用到与其相邻的四个数。例如,对于M[y] 点的二阶数值微分,需要访问下面四个数据:
M[x-1][y] M[x+1][y] M[y-1] M[y+1]
不考虑边界的话,这个倒是很容易,但是边界肯定要考虑的。对边界上的点需要特别处理。
问题是,要检测一个点需不需要特殊处理,就需要在 kernal 中写入 if 语句。听说 if 语句是很昂贵的。
并且,比如说,一个 5000x1000 的矩阵,其中的 4998x998 个点是不需要特别处理的,只对于周围的一圈,这里的 if 才有价值。
我现在想到的办法,就是写两个 kernal ,一个用于处理中间的,另一个加很多 if ,只对旁边一圈运行。随便他们效率怎么低吧,反正工作量也不大。
但是感觉很难看啊,求教,有更好的办法吗?
回答这个问题需要知道楼主的算法结构。但楼主没有给出。不过这不妨碍我们继续讨论。
(1)首先说,大部分线程的if…else途径是一致的(因为大部分点都是一种情况,少部分是另外一种)。例如楼主给出的矩阵规模,负责99.8%的点的线程都会总同一分支途径。所以“昂贵”的if分支基本可以无视。
所以基本无需考虑if带来的分支导致warp无法满负荷计算。
(2)那么判断带来的额外操作呢?这个要分情况讨论:
(2-1)如果楼主每个点上的“数值微分操作”步骤很多,例如需要计算100次。那么1次或者2次整数比较判断基本可以无视。他们带来的性能下降也就几个百分点。此时建议黑上if。
(2-1)如果楼主每个点上的“数值微分操作“步骤很少,例如就计算两三次。那么此时您的程序将严重卡在访存瓶颈上。此时if带来的额外计算会被掩盖在访存里,从来看上去是免费的。此时基本无性能下降影响,也建议黑上。
综合2说,因为if带来的额外计算(判断)基本是0影响。
因为(1)(2)支持此时带来的分支和额外计算导致的效率都基本可以无视。所以综合建议:
黑上if即可。
------------------未央宫遗址-----捡到的-----古------代-----陶------瓷--------------------
以上建议是就着楼主的原始疑问给出的。
下面给出我对于此问题的其他建议:
(1)因为楼主的数据具有典型的空间关系。建议考虑texture。
(2)因为楼主需要典型的边界处理,如果对越界的值可以用0代替。建议考虑texture.
综上,给出第二个建议:
建议楼主考虑使用texture(并使用cudaAddressModeBorder)寻址模式,以便优化访存效率,和texture寻址模式带来的自动越界处理,节省掉if。
请在1.x和3.x上着重考虑此建议。
并在2.x上根据实际使用效果考虑此建议或者保留原始算法。
当然,如果访存无问题,原来的写法也挺好。
嗯……看来我需要去研究下 texture 了,大神威武!谢谢!
那个,方式一就很好。第二个额外的建议(texture)只不过是可能会更好。
如果原始方式已经感觉满足了,没必要折腾第二个。有这功夫不如多多泡妞了。
访存确实是限制,每个点的计算量大概也就两三次的样子,但是整个数值微分过程会重复做上百万次,所以还是解决一下比较好……
:lol泡妞……很遥远的样子啊……