2.1 内容概要

  • 写程序的主要目标是使它能在所有可能的情况下都正确工作。程序员必须写出清晰简洁的代码,便于自己看懂及维护代码,也是为了他人能够快速检查代码和维护代码。
    程序运行得快是一个很重要的考虑因素,编写高效程序需要做到以下几点:
  • 1)我们必须选择一组适当的算法和数据结构;
  • 2)我们必须编写出编译器能够有效优化以转换成高效执行代码的源代码;该部分需要对优化编译器的能力和局限性的理解很重要;
  • 3)针对处理运算量特别大的计算,将一个任务分成多个部分,该部分可在多核和多处理器的某种组合上并行的运算。
  • 程序优化的第一步就是消除不必要的工作,让代码尽可能有效的执行所期望的任务,这包括消除不必要的函数调用、条件测试和内存引用。注意这些优化并不依赖于目标及其的任何具体属性。
  • 程序优化的第二步要了解处理器的运作,利用处理器提供的指令级并能能力,同时执行多条指令。程序员和编译器都需要理解目标机器的模型,指明如何处理指令,以及各个操作的时序特性。例如:编译器必须要知道时序信息,才能够确定是用一条乘法指令,还是用移位和加法的某种组合。现代计算机用复杂的技术来处理机器级程序,并行地执行许多指令,执行顺序还可能不同于他们在程序中出现的顺序。
  • 研究程序的汇编代码表示是理解编译器以及产生代码会如何运行的最有效手段之一。而仔细研究内循环的代码是一个很好的额开端,识别出降低性能的属性,例如过多的内存引用和对寄存器使用不当。从汇编代码开始,我们还可以预测什么操作会并行的执行,以及他们会如何使用处理器资源。然后,我们在回过头来修改源代码,试着控制编译器使之产生更有有效率的实现。

2.2 优化编译器的能力和局限性

  • 现代编译器运用复杂精细的算法来确定一个程序中计算的是什么值,以及他们是被如何使用的。然后会利用一些机会来简化表达式,在几个不同的地方使用同一个计算,以及降低一个给定的计算必须被执行的次数。GCC编译器向用户提供了一些对他们所使用的优化的控制,最简单的控制就是制定优化级别。例如:
  • -Og 调用GCC是让GCC使用一组基本的优化;
  • -O1 -O2 -O3 调用GCC让他使用更大量的优化。
  • 以上做法可以进一步提高程序的性能,也可能增加程序的规模,也可能使标准的调式共走更难对程序进行调式。而大多数使用GCC的软件项目,优化级别-O2已经成为了被接收的标准。
  • 另外编译器必须很小心的对程序只使用安全的优化,也就是说对于程序可能遇到的所有情况,在C语言标准提供的保证之下,优化后得到的程序和为优化的版本有一样的行为。限制编译器只进行安全的优化,消除了造成不希望的运行时行为的一些可能的原因,但这也意味着程序员必须花费更大的力气写出编译器能够将之转换成有效及其代码的程序。
  • 为了理解决定一种程序转换是否安全的难度,可看以下两个过程:
 void twiddle1(long *xp, long *yp){*xp += *yp;*xp += *yp;}void twiddle2(long *xp, long *yp){*xp += 2 * *yp;}
  • 初步看这两个过程似乎有相同的行为,都是将yp所指向内存的值两次加到指针xp所指向的内存中。仔细一看,函数twiddle2效率更高一些。它只要求3次内存引用(读xp,读yp,写xp),而twiddle1需要6次(2次读xp,2次读yp,2次写xp)。于是,如果编译器编译过程twiddle1,会认为基于twiddle2执行的计算能产生更有效的代码。
  • 但是考虑xp = yp的情况,twiddle1的计算结果是xp所指向内存的值的4倍,twiddle2计算结果则是xp所指向内存的3倍。而编译器不知道twiddle1会被如何调用,因此在编译过程则必须假设参数xp和yp可能会相等,其将不能产生twiddle2风格的代码作为twiddle1的优化版本。
  • 这种两个指针可能指向同一个内存位置的情况称为内存别名使用,在只执行安全的优化中,编译器必须假设不同的指针可能指向内存中的同一位置。这就造成了一个主要的妨碍优化的因素,其可能严重限制编译器产生优化代码机会的程序的一个方面,限制了可能的优化策略。
    示例:
 void swap(long *xp, long *yp){*xp = *xp + *yp;    /* x+y */*yp = *xp - *yp; /* x+y-x = y */*xp = *xp - *yp;  /* x+y-x - x */}

如果调用这个过程时xp=yp,会有什么样的效果?

第二个妨碍优化的因素是函数调用。示例如下:

 long f();long fun1(){return f()+f()+f()+f();}long fun2(){return 4*f();}
  • 初步看以上两个过程计算都是相同的结果,但是fun2只调用fun1次,而fun1需调用fun4次。以fun1作为源代码时,会很想产生fun2风格的代码。
    但是,考虑下面f的代码:
 long counter = 0;long f(){return counter++;}
  • 这个函数就会有副作用——它修改了全局程序状态的一部分。改变调用他的次数会改变程序的行为。特别地,假设开始时全局变量counter=0,对fun1的调用会返回0+1+2+3=6,而对fun2的调用会返回4*0=0。

  • 大多数编译器不会试图判断一个函数是否有没有副作用,其将会假设最糟的情况,就是保持所有的函数调用不变,也就是fun1的源代码不会被优化成像fun2中的样子,以提高程序的性能。

  • 备注:使用内联函数替换优化函数调用
    包含函数调用的代码可以用一个称为内联函数替换的过程进行优化,此时,将函数调用替换为函数体。我们通过替换掉对函数f的四次调用,展开fun1的代码:

 long fun1in(){long t = counter++;    /* +0 */long t = counter++; /* +1 */long t = counter++; /* +2 */long t = counter++; /* +3 */return t;}
  • 以上的做法减少了函数调用的开销,也允许对展开的代码做进一步的优化。于是编译器可以统一fun1in中对全局变量counter的更新,产生这个函数的一个优化版本:
 long fun1opt(){long t = 4 *counter + 6;counter += 4;return t;}
  • 在编译时使用命令行选项“-finline”、“-O1”或者更高级别编译选项时,最近的GCC版本会尝试进行以上形式的优化。目前来说,GCC只尝试在单文件中定义的函数的内联。其将无法应用于常见的情况,及一组库函数在一个文件中定义,却被其他文件内的函数所调用。
  • 然而在某些情况下,最好能够阻止编译器执行内联替换。一种情况是用符号调试器来评估代码,如GDB调试程序,如一个函数已经用内联替换优化过了,则任何对这个调用进行追踪或设置断点的尝试都会失败。另外一种情况是用代码剖析的方式来评估程序的性能。
  • 针对以上的描述,我们可知就优化能力来说,GCC编译器被认为是胜任的,但其优化性能并不是特别的突出,他能完成基本的优化,但不会对程序进行更加“有进取心的”编译器所做的那种激进变换。因此,我们在编写代码要是一种不会让编译器产生歧义的代码,在不影响功能的基础上尽可能的编写出一种能让编译器生成高效的代码。

C程序性能优化方法(一)相关推荐

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

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

  2. C++性能优化(一)——应用程序性能优化简介

    一.程序性能优化简介 1.程序性能优化简介 在计算机发展的早期阶段,硬件资源相对而言是非常昂贵的,CPU运行时间与内存容量给程序开发人员设置了极大限制.因此,早期的程序对运行性能和内存空间占用的要求是 ...

  3. asp.net程序性能优化的七个方面

    asp.net程序性能优化的七个方面 一.数据库操作 1.用完马上关闭数据库连接 访问数据库资源需要创建连接.打开连接和关闭连接几个操作.这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器 ...

  4. 大主子表关联的性能优化方法

    [摘要] 主子表是数据库最常见的关联关系之一,最典型的包括合同和合同条款.订单和订单明细.保险保单和保单明细.银行账户和账户流水.电商用户和订单.电信账户和计费清单或流量详单.当主子表的数据量较大时, ...

  5. 《C++应用程序性能优化::第五章动态内存管理》学习和理解

    <C++应用程序性能优化::第五章动态内存管理>学习和理解 说明:<C++应用程序性能优化> 作者:冯宏华等 2007年版. 2010.8.29 cs_wuyg@126.com ...

  6. C++应用程序性能优化(三)——C++语言特性性能分析

    C++应用程序性能优化(三)--C++语言特性性能分析 一.C++语言特性性能分析简介 通常大多数开发人员认为,汇编语言和C语言比较适合编写对性能要求非常高的程序,C++语言主要适用于编写复杂度非常高 ...

  7. HBase性能优化方法总结(四):数据计算

    本文主要是从HBase应用程序设计与开发的角度,总结几种常用的性能优化方法.有关HBase系统配置级别的优化,可参考:淘宝Ken Wu同学的博客. 下面是本文总结的第四部分内容:数据计算相关的优化方法 ...

  8. HBase性能优化方法总结(4):读表操作

    来自:http://www.cnblogs.com/panfeng412/archive/2012/03/08/hbase-performance-tuning-section3.html 本文主要是 ...

  9. Hibernate程序性能优化的考虑要点

    Hibernate程序性能优化的考虑要点 Tag:java,j2ee,hibernate,O/R mappling, spring,性能,效率 本文依照HIBERNATE帮助文档,一些网络书籍及项目经 ...

最新文章

  1. 网络工程师如何才能实现职位晋升
  2. python大神-国内某Python大神自创完整版,系统性学习Python
  3. Django资源大全
  4. 027_JavaScript数组迭代
  5. Winform开发框架里面使用事务操作的原理及介绍
  6. 活动 | Daung~!他们用产品思维改变医疗挂号问题
  7. Java中的基本数据类型转换(自动、强制、提升)
  8. 修改窗口图标 AfxRegisterWndClass()
  9. struts框架学习过程中的问题。
  10. 零基础直接学Python入门IT合适吗?
  11. ACCESS数据库C#操作类(SQLHELPER修改版)——转自网上
  12. Thought Works 总结
  13. 1.3端口扫描:利用Nmap工具进行端口扫描
  14. matlab有限差分法求解温度场,动静压轴承油膜温升MATLABFLuENT有限差分法硕士论文...
  15. 饿了么移动APP的架构演进
  16. springboot接入微信,支付宝支付
  17. 谷歌google浏览器升级后发生个人资料错误 发送反馈解决方法
  18. “壮士断腕”无人驾驶能够拯救苹果的内忧外困吗?
  19. Python基于PHP+MySQL的个人网页设计与实现
  20. ggplot2设置坐标轴范围_ggplot2|详解八大基本绘图要素

热门文章

  1. 非线性优化求解器IPOPT
  2. ffmpeg 修改视频封面
  3. linux系统字符设备文件类型,Linux文件类型
  4. 分布式机器学习:同步并行SGD算法的实现与复杂度分析
  5. erp系统erp软件
  6. python bytearray
  7. Android手机Log
  8. Adobe Flash Builder 4 注册码
  9. 微信支付代理加盟 开启商家移动支付时代
  10. 计算机毕设之化妆品管理系统