参考书籍《深入理解计算机系统》
1 高效程序的基础
- 数据结构和算法:比如hash_map的查找效率会高于map;1加到100用公式(1 + 100)* 50的效率高于循环累加
- 源代码能够被编译器有效优化成高效可执行代码:对于这一点需要理解优化编译器的能力与局限性,C的一些特性——比如执行指针运算和强制类型转换等——使得优化很困难
2 优化编译器的能力和局限性
-
编译优化:编译优化会更改代码的,在优化中,有不同的选项,有些是牺牲时间换空间,有些是牺牲空间换时间;编译优化非常繁杂和易错,最激进的优化策略可能会带来错误,如果想采用最激进的策略进行优化,编码阶段就必须有编码规范约束,对开发人员的要求会较高 注:这部分内容可以看一下编译原理,东西比较多,这里只介绍简单的概念 -
编译过程 1.预处理生成.i文件(预处理器); 2.将预处理后的文件转换成汇编语言,生成.s文件(编译器); 3.将汇编转换成机器代码,生成.o文件(汇编器); 4.链接目标代码,生成可执行程序(连接器)。 -
编译优化等级 -O0 无优化; -O1 基本优化,编译器会在不花费太多编译时间(不显著增加)的同时试图 生成更快更小的代码; -O2 包含-O1的优化并增加了不需要在目标文件大小和执行速度上进行折衷的优化,此选项将 增加编译时间和目标文件的执行性能 (编译器不执行循环展开以及函数内联),此选项是推荐的优化等级; -Os(-O2.5)在 -O2 选项的基础上(基本包含所有,除了对齐优化等),执行 优化程序空间大小 的优化选项,专门优化目标文件大小。可能产生些许问题,不推荐的优化等级; -O3 这是最高最危险的优化等级,用这个选项会延长编译代码的时间,产生更大体积更耗内存的二进制文件,大大增加编译失败的机会或不可预知的程序行为(包括错误),在 gcc4.x 中使用-O3是不推荐的。 注1:编译优化的具体实现跟编译器也有关系,本文所有编译器如未特殊说明,均指gcc编译器 注2:不同编译优化等级其实是不同编译优化选项的一些集合,比如-floop-optimize(优化循环)、-fif-conversion(优化if-then语句)等 -
编译优化的局限性: 1.可能会改变正确的程序行为; 2.编译器对程序的行为、使用环境了解有限; 3.会增加编译时间。
3 程序优化的方法
- 消除低效的循环:把不必要的语句提到循环外面
- 降低循环开销:展开循环
- 减少过程调用
- 消除不必要的存储器引用:引入临时变量来保存中间结果,只有在最后值计算出来时才将结果存放在数组或全局变量中;
- 利用指针和数组
- 提高并行性:分割循环
4 程序性能剖析工具
- Unix提供GPROF
功能:这个程序可提供两种形式的信息:程序中每个函数花费了多少CPU时间;每个函数被调用的次数 使用步骤: 1.加上编译命令行选项 -pg:gcc -O2 -pg prog.c -o prog ; 2.正常执行程序:./prog ,运行会比正常的稍微慢一点,会生成一个gmon.out文件; 3.调用GPROF来分析gmon.out中的数据:gprof prog 注:GPROF的计时是基于简单的间隔计数机制,不是很准确;默认情况下不会对库函数的调用
|