cuda c权威编程指南_CUDA编程入门(六)展开循环继续优化

这一节我们还是要继续优化并行归约的程序。(惊不惊喜意不意外.jpg)

不过不用担心,这一篇我们会从另外几个角度来进行优化,与上一篇并不重复。而且反复优化程序对我们理解CUDA编程是很有帮助的,还请大家坚持看下去。

展开循环以隐藏延时

现在使用高级语言编程时,我们已经不会刻意去进行循环展开了,因为这件事会由编译器帮我们完成。但在CUDA编程中,循环展开具有很重要的意义,它能给线程束调度器提供更多可用的线程束,以帮助我们有效地隐藏延时。

于是我们可以使用循环展开的方法,对并行归约的程序再来一波优化。

我们之前只是用一个线程块来处理一个小数组,我们称其为一个数据块。如果我们使用一个线程块手动展开两个数据块的处理,那会怎样呢?先给个结论,这样通过减少指令消耗和增加更多的独立调度指令,更多的并发操作被添加到流水线上,以产生了更高的指令和内存带宽。反映在宏观上就是程序执行的总体时间变少了。

改进后的核函数代码在这里:

__global__ 

从概念上来讲,可以把它作为归约循环的一个迭代,此循环可在数据块间进行归约。

如果每个线程处理两个数据块,那么我们需要的线程块总量会变为原来的一半,因此主函数也要对应修改。

看上去,这样处理后线程块减少了,与我们之前要使用尽量多线程块的理论不符。但实际我们通过这种方式,让一个线程中有更多的独立内存加载/存储操作,这样可以更好地隐藏内存延时,更好地使用设备内存读取吞吐量的指标,以产生更好的性能。所以我们编程时,各个策略要针对实际情况结合使用。

执行结果如下图。

f98d516137f7660cfa40c319ee70ab6f.png
展开2块

相比于上篇最后的优化结果,程序执行速度再次获得了不小的提升,从1.37ms提升到0.8ms,1.7倍加速比。

既然一个线程块处理2个数据块能获得这么高的加速比,那么处理4个,8个呢?代码不赘述了,我们直接来看结果。

b5a85f8703a781c27713bbfc49f00b95.png
展开8块

随着处理数据块数量的增多,处理时间不断降低。不过随着设备内存吞吐量逐渐到达极限,这个时间就不会继续降低了。

总结一下,为了隐藏延时,我们需要合理地增加一个线程块中需要处理的数据量,以便线程束调度器进行调度

展开线程

我们可以再进一步想想,当执行到最后几次迭代时,当只需要32个或更少线程时,每次迭代后还需要进行线程束同步。为了加速,我们可以把这最后6次迭代进行展开,使用下面的语句:

if

这样就避免了执行控制循环逻辑和线程同步逻辑的时间。

把这段添加到上面的代码中,然后修改一下之前的迭代次数,运行得到如下结果,可以看到又加速了不少。

fa77e84280d1012139855817fffd9adc.png
展开线程

完全展开

到目前位置,我们的代码里只剩一个循环了。不过理论上如果编译时已知一个循环中的迭代次数,就可以把循环完全展开。因为我们的核函数中的循环迭代次数是基于一个线程块维度的,而且一个线程块支持最大1024个线程,所以我们可以将这个循环进行完全展开。核函数代码如下:

__global__ 

运行一下看看结果:

a94398810d645c59b26c2a470ef1ac12.png
完全展开

不过结果令人意外,完全展开后反而时间增加了,这和书上的结果不太一样,看来nvcc编译器后来又做了很多新的优化。

优化成果小结

画个表格总结一下从最初版本到现在我们的加速情况。

15a99eaebaffcdb5b3c411ec1cb59c0e.png
优化效果总结

优化效果还是很明显的,最终我们在初版代码的基础上获得了8.21倍的加速。再次感谢《CUDA C编程权威指南》的作者能为我们提供这么精彩的例子。

最后,本篇的代码放在这里:

https://github.com/ZihaoZhao/CUDA_study/tree/master/Reduction3

看到这里,不用说大家应该也有了一定体会,对于并行编程而言,优化是无止境的。可以说,不考虑编程时间的优化都是耍流氓。在优化中我们往往会发现有些改变是“唾手可得”的,这些改变会很容易,而且带来可观的加速。当这些被改进掉后,就必须采用更复杂的策略来进一步优化,这会花费我们更多的时间,代码可读性会变差,也会引入更多潜在的bug。总体来说,如果以我们的编程时间为x轴,加速比为y轴,我们能获得的往往是一个对数曲线,这一点是我们做实际项目时需要铭记的。

长呼一口气,我们终于把并行归约的程序地优化地差不多了,能看到这里的你真的不容易,来评论留个言,我们交个朋友。顺便感慨一下,学并行编程算法的人比学深度学习算法的人少多了,我觉得是好事,至少证明这里没那么大泡沫,大家共勉。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值