以C语言为例的程序性能优化 --《深入理解计算机系统》第五章读书笔记
其实大多数的编译器本身就能提供一些简单的优化,比如gcc就能通过使用 -O2 或者 -O3 的选项来优化程序。但编译器的优化始终也是有限,因为它必须小心翼翼保证优化过程不对程序的功能有改动。故而程序员本身应该对程序有优化意识。在我看来,这也是应该有的一种良好的编程习惯。
几种比较简单的优化措施:
1.代码移动
将要执行多次(比如在循环中)但计算结果不会改变的计算,移动到代码前面不会多次求值的部分。举一个比较极端的例子:
/* convert string to lowercase: slow*/
void lower( char *s ){
int i;
for( i = ;i < strlen(s);i++ )
if( s[i] >= 'A' && s[i] <= 'Z' )
s[i] -= ( 'A' - 'a');
}
因为C语言的字符串是以null结尾的,函数strlen也必须一步一步得检查这个序列,直到遇到null字符。那么假象一下,如果字符串s是一个很长的字符串,那么这个函数自然会造成许多不必要的开销!!
故而在循环体内,要注意将计算结果不改变的计算移动到前面避免多次重复计算。
优化代码:
/* convert string to lowercase: faster*/
void lower( char *s ){
int i;
int len = strlen(s);
for( i = 0;i < len;i++ )
if( s[i] >= 'A' && s[i] <= 'Z' )
s[i] -= ( 'A' - 'a'); }
2.消除不必要的存储器引用
在C语言中用指针变量读写是用CPU寄存器间接寻址然后从内存中读写,而使用函数内部的局部变量,则是使用CPU中的通用寄存器。而主存读写和CPU内部通用寄存器的寻址的速度相差数十倍的。举一个小例子
for( i = 0;i < len;i++ ){
*dest = *dest + data[i];
}
这个循环体每次都会从主存中读写,优化如下:
int acc;
for( i = 0;i < len;i++ ){
acc = acc + data[i];
}
*dest = acc;
这样就会使那个指针只写入一次,而acc变量在cpu的执行过程中是使用cpu内部通用寄存器读写,故而能加快速度。
3.循环展开
循环展开,顾名思义就是将一次一步的迭代循环展开成一次两步或更多,减少迭代次数。循环展开从两个方面改善程序的性能,首先,它减少了不直接有助于程序结果的操作的数量,比如循环索引计算和条件分支。其次,它提供了一些方法,可以进一步变化代码,减少计算中关键路径上的操作数量。比较如下两个函数,第一个为常规循环,第二个为循环展开函数,
//normal function to add all element of v
void combine1( vec_ptr v,data_t *dest ){
int i = ;
long int length = vec_length( v );
data_t *data = get_vec_start( v );
data_t acc = IDENT;
for( i = ;i < length;i++ ){
acc = acc + data[i];
}
*dest = acc;
}
//unroll loop by 2
void combine2( vec_ptr v, data_t *dest ){
int i;
long int length = vec_length( v );
loing int limit = length -1;
data_t *data = get_vec_start( v );
data_t acc = IDENT; for( i = 0;i < limit;i += 2 ){
acc = ( acc + data[i] ) + data[i+1];
} for( ;i < length;i++ ){
acc = acc + data[i];
} *dest = acc;
}
第二个函数将循环展开,并在最后检查会不会遗漏。减少了一些关键步骤,故而优化了程序。
4.提高并行性
在cpu中,程序被翻译成汇编指令,但却并不是一条一条指令按顺序执行的,而是流水线并发执行的,即多条不相关指令共同执行。这是cpu的机器特性,而我们要做的,就是多多利用这种机器特性。
让我们来分析程序的combine2中的核心循环内部语句:acc = ( acc + data[i] ) + data[i+1];在这个循环中,data[i+1]的计算必须放在( acc + data[i] )之后,因为它们是相互关联的,这明显是不利于程序的并行操作,改进如下。
//unroll loop by 2,2-way parallelism
void combine3( vec_ptr v, data_t *dest ){
int i;
long int length = vec_length( v );
loing int limit = length -1;
data_t *data = get_vec_start( v );
data_t acc0 = IDENT;
data_t acc1 = IDENT; for( i = 0;i < limit;i += 2 ){
acc0 = acc0 + data[i];
acc1 = acc1 + data[i+1];
} for( ;i < length;i++ ){
acc0 = acc0 + data[i];
} *dest = acc0 + acc1;
}
这段代码将acc拆分成acc0和acc1,使程序得以并发同时计算,最后再将两组结果想加,提高程序性能。
代码优化通常都会带来可读性的降低,如何取舍应该好好考虑清楚,必要时刻,或许应该多加一些注释说明。
以C语言为例的程序性能优化 --《深入理解计算机系统》第五章读书笔记的更多相关文章
- [JAVA] java程序性能优化
一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...
- iOS程序性能优化
iOS程序性能优化 一.初级 使用ARC进行内存管理 在iOS5发布的ARC,它解决了最常见的内存泄露问题.但是值得注意的是,ARC并不能避免所有的内存泄露.使用ARC之后,工程中可能还会有内存泄露, ...
- iOS 程序性能优化
前言 转载自:http://www.samirchen.com/ios-performance-optimization/ 程序性能优化不应该是一件放在功能完成之后的事,对性能的概念应该从我们一开始写 ...
- [转]C#程序性能优化
C#程序性能优化 1.显式注册的EvenHandler要显式注销以避免内存泄漏 将一个成员方法注册到某个对象的事件会造成后者持有前者的引用.在事件注销之前,前者不会被垃圾回收. private v ...
- Java程序性能优化之性能概述
性能的基本概念 一).什么叫程序的性能? 程序运行所需的内存和时间. 二).性能的表现形式: 1).执行速度: 程序的反应是否迅速,响应时间是否足够短. 2).启动时间:程序从运行到可以处理正常业务所 ...
- [深入浅出Cocoa]iOS程序性能优化
本文转载至 http://blog.csdn.net/kesalin/article/details/8762032 [深入浅出Cocoa]iOS程序性能优化 罗朝辉 (http://blog.csd ...
- C++ 应用程序性能优化
C++ 应用程序性能优化 eryar@163.com 1. Introduction 对于几何造型内核OpenCASCADE,由于会涉及到大量的数值算法,如矩阵相关计算,微积分,Newton迭代法解方 ...
- Java程序性能优化技巧
Java程序性能优化技巧 多线程.集合.网络编程.内存优化.缓冲..spring.设计模式.软件工程.编程思想 1.生成对象时,合理分配空间和大小new ArrayList(100); 2.优化for ...
- 《Java程序性能优化:让你的Java程序更快、更稳定》
Java程序性能优化:让你的Java程序更快.更稳定, 卓越网更便宜,不错的书吧
随机推荐
- 大搜车知乎live中的面试题结题方法记录
1.HTML&CSS(分别10分) 1. 一个div,宽度是100px,此时设置padding是20px,添加一个什么css属性可以让div的实际宽度仍然保持在100px,而不是140px? ...
- 开发中使用UEditor编辑器的注意事项
最近在一个刚结束的一个项目中使用到了UEditor编辑器,下面总结一下遇到的问题以及使用时需要注意的地方: 1. 使用UEditor插件需要先对其进行路径配置: 在ueditor.config.js文 ...
- 2017 Multi-University Training Contest - Team 9 1004&&HDU 6164 Dying Light【数学+模拟】
Dying Light Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Tot ...
- Codeforces 626C
...
- 三维dp&codeforce 369_2_C
三维dp&codeforce 369_2_C 标签: dp codeforce 369_2_C 题意: 一排树,初始的时候有的有颜色,有的没有颜色,现在给没有颜色的树染色,给出n课树,用m种燃 ...
- 最长上升子序列(LIS) dp学习~3
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1087 Super Jumping! Jumping! Jumping! Time Limit: 200 ...
- Xshell无法连接到LINUX虚拟机
首先与遇到的情况是,在虚拟机下安装了Linux后,xshell无法连接远程的虚拟机. 我遇到的情况是虚拟机可以ping 主机,主机确ping不了虚拟机. 使用的VM设置了两个网卡,一个nat 一个h ...
- FineReport父子格实现动态参数注入
"深入学习FineReport后发现其功能及其强大,之前使用存储过程实现的报表完全可以使用FineReport本身的功能实现. 当你需要的表名,查询条件等均未知的时候,使用"动态参 ...
- Oracle忘记密码如何重
---恢复内容开始--- 昨天安装Oracle11g R2的时候给scott用户设置密码,当时没有显示而且还只以输入一次,可能密码输入错误,结果今天用scott用户登录果然密码不对,还好sys和sys ...
- Spark算子--reduceByKey
reduceByKey--Transformation类算子 代码示例 result