其实大多数的编译器本身就能提供一些简单的优化,比如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语言为例的程序性能优化 --《深入理解计算机系统》第五章读书笔记的更多相关文章

  1. [JAVA] java程序性能优化

    一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...

  2. iOS程序性能优化

    iOS程序性能优化 一.初级 使用ARC进行内存管理 在iOS5发布的ARC,它解决了最常见的内存泄露问题.但是值得注意的是,ARC并不能避免所有的内存泄露.使用ARC之后,工程中可能还会有内存泄露, ...

  3. iOS 程序性能优化

    前言 转载自:http://www.samirchen.com/ios-performance-optimization/ 程序性能优化不应该是一件放在功能完成之后的事,对性能的概念应该从我们一开始写 ...

  4. [转]C#程序性能优化

    C#程序性能优化 1.显式注册的EvenHandler要显式注销以避免内存泄漏 将一个成员方法注册到某个对象的事件会造成后者持有前者的引用.在事件注销之前,前者不会被垃圾回收.   private v ...

  5. Java程序性能优化之性能概述

    性能的基本概念 一).什么叫程序的性能? 程序运行所需的内存和时间. 二).性能的表现形式: 1).执行速度: 程序的反应是否迅速,响应时间是否足够短. 2).启动时间:程序从运行到可以处理正常业务所 ...

  6. [深入浅出Cocoa]iOS程序性能优化

    本文转载至 http://blog.csdn.net/kesalin/article/details/8762032 [深入浅出Cocoa]iOS程序性能优化 罗朝辉 (http://blog.csd ...

  7. C++ 应用程序性能优化

    C++ 应用程序性能优化 eryar@163.com 1. Introduction 对于几何造型内核OpenCASCADE,由于会涉及到大量的数值算法,如矩阵相关计算,微积分,Newton迭代法解方 ...

  8. Java程序性能优化技巧

    Java程序性能优化技巧 多线程.集合.网络编程.内存优化.缓冲..spring.设计模式.软件工程.编程思想 1.生成对象时,合理分配空间和大小new ArrayList(100); 2.优化for ...

  9. 《Java程序性能优化:让你的Java程序更快、更稳定》

    Java程序性能优化:让你的Java程序更快.更稳定, 卓越网更便宜,不错的书吧

随机推荐

  1. Hyperledger Fabric Model——超级账本组成模型

    超级账本组成模型 本文主要讲述Hyperledger Fabric的关键设计特性,并细述如何实现了一个全面的.可定制的企业级区块链解决方案: 资产定义--资产这里理解为任何具有货币价值的东西,它们都可 ...

  2. Django----->inclusion_tag的使用

    一种比较普遍的tag类型是只是渲染其它模块显示下内容,这样的类型叫做Inclusion Tag. 常用的模板标签是通过渲染 其他 模板显示数据的. 比如说,Django的后台管理界面,它使用了自定义的 ...

  3. html笔记2

    html css的用法 <style type="text/css">代表我要使用css了 <html> <head> <style ty ...

  4. Java Socket获取本机的InetAddress实例

    package com.immooc;/* * InetAddress类 */import java.net.InetAddress;import java.net.UnknownHostExcept ...

  5. 51 Nod 1029 大数除法【Java大数乱搞】

    1029 大数除法 基准时间限制:4 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 给出2个大整数A,B,计算A / B和A Mod B的结果.   Input 第1行:大数A ...

  6. HDU 1711 Number Sequence(KMP裸题,板子题,有坑点)

    Number Sequence Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  7. 2017 ICPC/ACM 沈阳区域赛HDU6223

    Infinite Fraction Path Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java ...

  8. JAVA开发中遇到的异常总结

    最常见的五种异常:必会,面试题: 算术异常类:ArithmeticExecption 空指针异常类:NullPointerException 类型强制转换异常:ClassCastException 数 ...

  9. Node.js框架 —— Express

    一.安装express 1.需先安装express-generator npm install -g express-generator 2.安装express npm install -g expr ...

  10. [机器学习]模型评价参数,准确率,召回率,F1-score

    很久很久以前,我还是有个建筑梦的大二少年,有一天,讲图的老师看了眼我的设计图,说:"我觉得你这个设计做得很紧张".当时我就崩溃,对紧张不紧张这样的评价标准理解无能.多年后我终于明白 ...