一个多核程序的优化方法小结
最近一个月时间,周围的所有人在做的是一件事,优化。让一个物理模拟的程序尽可能快的运行在多核平台上。一个月前,知道要做什么,但心里完全没有底,一个月后,坐在计算机前看着程序运行的录像时,心里还是挺有成就感的。当然,优化是一条无止境的路,即便程序做到目前的状态依然有很大的提升空间,这里只是简单总结一下之前用到的一些方法。
硬件
CPU
说过这是一个多核平台的优化,所以,多核CPU是肯定的了。身边这台机器是两个4核CPU,也就相当于有8个核。但是,多核CPU显然不会像单核CPU提升频率那样可以坐享其成。不做修改的结果只能是看着一个核累死,其它的核闲得无聊。所以,有了多核CPU,还要有软件配合。
显卡
另外一个提升的是显卡,因为程序本身有显示的部分,而且是一个3D的图像。后来证明,计算的部分很快,显示的部分成了瓶颈,原来的显卡程序只能运行在简单的模式下,为了能够在更复杂的模式下让程序流畅的运行,换了一块五大三粗的显卡。回忆了一下,为了这个程序而在换的显卡就有四块之多。
程序
程序的部分才是我们真正着力去做的事情。
分离计算和显示
这是在通常的桌面程序最容易想到的方案,即便不是为了优化。分离二者之后,就不会出现因为计算而造成的界面失去响应的情况。这里用到的技术,主要是双缓冲,计算线程将算的结果放置到写缓冲中,然后翻转。用这种方式将二者分开,避免原来因为同步造成的其中一个的缓慢影响到另外一个。
计算部分
程序的核心是计算部分,它真正决定程序的效果。
多线程
如果软件不修改,只有多核的CPU本质上不会带来什么提升。现阶段,利用多核最好的方式就是多线程。原本打算自己来写线程管理的部分,考虑到复杂度,最终用的是OpenMP,只要几条编译指令,程序便拥有了多线程的本事。
数据结构
很多数据结构在单核的情况下,表现良好,而在多核的情况下就稍显不足了,比如链表。如果需要对链表所有元素进行处理,在单核情况下,遍历就好了,而在多核的情况下,简单的遍历是不能充分发挥多核的优势,而且往往需要用锁保证并发访问的正确性。如果用数组的话,只要能够进行正确的划分,比如,每个线程处理一段,那多核的优势便会发挥出来。所以,有些时候,为了发挥多核的威力,需要适当的调整一下数据结构。
显示部分
本质上来说,显示部分的调整并不能让程序算得更快,但它却可以给人们觉得“程序算得更快”。
局部视图
当程序只显示一个局部的时候,把所有视图都画出来其实没有什么意义,而且还要浪费大量的计算资源,所以,只绘制可以显示的一小部分即可。
远端视图
程序中的物体是一个3D模型,但是,我们都知道近大远小的道理,当它看上去离我们很远的时候,根本看不出来到底是个什么东西。所以,在这种情况下,我们可以用简单的模型替代复杂模型,提高处理性能。
软件
编译器
为了压榨程序的性能,一个好的编译器自然是不可或缺的。所以,我们选择了号称能生成Intel平台最好性能代码的ICC。除了编译器本身的优异,它对OpenMP的支持也让我们可以放心这个方案,另外,它还提供对SSE系列的支持,可以省去思考汇编的烦恼。
Profiler
当大的方面已经就绪,剩下的细节就是Profiler展现本事的地方了。VTune是个不错的选择,可以让把程序运行的状况清晰的展现出来。通过对VTune捕获事件的定制,我们可以要求它给出我们希望了解的内容,比如缓存命中的状态,不看不知道,原来因为Cache Missing造成的损失还是不少的。于是,它为我们进一步调整提供了一个方向。
http://dreamhead.blogbus.com/logs/4945878.html