为什么要优化?
能够运行的程序不一定是可以发布的程序,功能齐全而且能够以用户可以接受的效率运行、消耗可以接受的资源的才是可以发布的程序,所以,在保证程序功能正确齐全的前提下,可能还需要做代码优化。
何时优化?
过早的优化往往带来代码可读性下降,引入bug,一般在项目后期才考虑“系统的优化”,但是在coding的过程中,程序员应该有意识的采用高效的算法,在一些编程细节上采用优化的代码风格。程序整个体系结构对效率的影响相当大,所以,不要以为优化只是最后的事情。
优化到什么程度?
需要一个benchmark,设立优化的目标,一般以用户的体验为基准,不能盲目的优化。
优化什么代码?
10%-90%现象,10%的代码消耗的90%的资源,只有对这10%的代码进行优化才有意义。对于整个程序影响不大的代码,有时间优化当然好,但是没有必要放在高优先级位置。
如何找到那10%的代码?
简单的程序可以通过肉眼观察发现热点(hotspot,最消耗时间和资源的代码段),复杂的程序就超出人的智力范围了,需要Profiler来发现热点。而且,优化的过程就是发现热点,修改代码,检查性能的循环过程,很有可能程序员主管上觉得提高性能的改变实际上降低了性能,科学的办法就是用profiler发现热点,分析热点,修改热点代码,然后马上用profiler重新测量热点执行效率,验证代码修改是否真的提高效率。
什么是Profiler?
Profiler也就是剖析器,它能够获得被profile的程序运行数据,比如函数或者指令的执行时间和执行次数,程序员由此可以判断哪些函数或者指令是热点。
Profiler的工作原理?
最有意思的部分:)
Profiler分两种,被动的和主动的。被动的Profiler对被剖析的程序不作任何修改,用取样(sampling)的方法获得运行数据;主动Profiler需要对程序进行一些修改。
被动的Profiler好比拿着秒表的教练,在一旁监测运动员成绩,不会对运动员有什么干扰。原理上,可以通过设置定时中断,每隔一段时间中断被剖析程序,读取相关数据,然后让其继续。这种采样的方式的精确度很大程度上取决于中断频率的选择,太频繁了会干扰程序的正常执行,不频繁又不会获得精确数据。从某Profiler的生产商的白皮书认为被动式Profiler缺点大于优点,鉴于这个生产商有自己的主动式Profiler,这点不敢完全苟同:)
主动式Profiler好比科技型教练,在运动员身上安上一些设备,然后通过这些设备全面了解运动员的速度、心跳、体温等等数据,获得的数据自然比用秒表获得的要多得多,但是如果放在运动员身上的数据太多,也会影响运动员的表现,从而获得不实的数据。主动式Profiler通过在source code或者object文件中插入一些小代码来记录程序运行数据,还有更加高级的Profiler既不修改source code,也不修改object文件,而是通过动态的把可执行代码拆开成中间结果,插入一些观测点,然后产生新的临时执行代码。
修改source code,可以是程序员显示的在代码中加入宏来实现,也可在预处理阶段插入,现在compiler的提供商一般都附送一个profiler,连gcc都有一个gprof。修改object文件差不多,只不过时机不同。
需要说明的是,主动式Profiler也可能导致测量结果和实际情况不符合,因为文件大小不一样,函数偏移不一样。
主动式Profiler能够获得函数或者代码行甚至机器语言命令的执行效率,有两个衡量方法,一个是执行时间,另一个是执行的机器时钟周期。执行时间很可能不准,因为插入的代码会消耗时间,系统中其他运行的程序也会占用CPU,但是对于函数级的代码段,可以通过多次运行,去掉最高分,去掉最低分,去平均值的方法获得近似结果,对于单条代码行或单条汇编代码,就不太合适了,应该以机器时钟周期为单位测量。不过,现在的CPU采用的流水线执行方式,当出现条件跳转时,获得的时钟周期也可能不准。
唉,优化真的不是容易活啊