Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2177605
  • 博文数量: 436
  • 博客积分: 9833
  • 博客等级: 中将
  • 技术积分: 5558
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-29 10:27
文章存档

2013年(47)

2012年(79)

2011年(192)

2010年(118)

分类: C/C++

2012-11-26 00:41:32

    对“优化程序性能”这章进行了学习,并不能算是深度的学习,很多概念还是不太明白。
    这一章大致可以分为两个部分,第一部扥的性能优化是与机器无关的,第二部分是与机器有关的,相比较而言第一部分能好理解一些。
    与机器无关的性能优化可以部分依赖于编译器的优化,但是当遇到一些特殊情况是会影响编译器优化,如存储器的别名使用,以及当被多次重复调用的函数存在修改全局程序状态的副作用时等等,这些都可能会影响编译器的优化判断,因为大多数编译器是无法判别这些“副作用”的,此时则需要程序员自己进行手动的优化。
    根据书中介绍,性能的优化可以从以下几个方面来进行:存储器别名使用; 减少循环中的重复计算; 减少过程调用和不必要的存储器引用。关于存储器引用部分的实例有点不能理解,源代码为 *dest = *dest OPER data[i];( 存在于for循环中)  为了减少对存储器*dest的重复引用,将代码改为 data_t x = IDENT; *dest = IDENT; x = x OPER data[i]; *dest = x; 即在目标寄存器和结果中间设置了一个中间变量,在for循环中完全消除了对寄存器的引用,从CPE的值来看,有明显的效率改善,但是最终结果也因此改变了,优化前的最终结果可以说与目标寄存器的内容息息相关,但是优化后最终结果与目标寄存器内的内容就没关系了,因此不明白这样的优化是不是有点改变了代码的“初衷”?
    与机器有关的性能优化,由于对计算机内部构造的生疏,看起来有点难懂,其中投机执行技术觉得挺有趣,设计的有点小巧妙,尤其是与寄存器重命名的结合,更是使分支预测失败时状态的更改更为方便。但是对于重命名表只包含关于有未进行写操作的寄存器条目这一机制不是很清楚,是当寄存器完成写操作以后相关的寄存器条目就会清空吗?
    机器的配置能够成为代码优化的瓶颈,寄存器数目,功能单元性能,运行时间,这些都是程序员无法改变的,只能在资源约束下尽力避免。如提高并行性。其中提高代码的并行性可以分为迭代分割和循环展开,所谓循环展开就是尽量在一次循环中进行多的数据操作,以减少循环的开销。而迭代分割则是把一个迭代按一定规律分割成多次迭代,最后结合,直接提高了程序的并行性。“迭代分割利用了加载单元和整数乘法器的流水线化的能力”(对于流水线化的概念不是很明白)。当这两种方法结合起来是效率的提升更是明显。
    还有一个很大的问题就是CPE,每元素的周期数,这个概念在书中一直提到,却不知道怎么来的,查到的资料中算法是这样的"If you want to know how long it needs, you should measure it. Execute the loop some about 10^10 times, take the time it needs and multiply by the clock frequency. You get the total count of cycles, divide by 10^10 to get the number of clock cycles per loop iteration." 我理解的话就是一个循环的平均使用时钟周期,但是不知道是不是理解错了,觉得这似乎与”每元素“无关,而是”每函数“或者说”每循环“,但是书中这样解释”机器每四个时钟产生两个结果,得到了理论上的CPE2.0  “  这样的话似乎又是对的,每得到一个结果不就相当于一次函数或者循环的执行吗, 但是后来又看到以下内容:”比如一个数组int array[50],它在函数f()中被用于计算,最后f()所用去的cpu clock为100, 那么函数f()的CPE为100/50=2.0;  为什么不采用每次循环的周期数而是采用每元素的同期数呢,因为可能会出现循环展开的情况。“ 此时的则将”每元素“与”每循环“区分开来了。
    后面的剖析函数部分则没什么了解了。
    看到这里疑问很多,但是最大的疑问始终是一个,就是如何真正的把这些运用到平常代码的优化中,有种纸上谈兵终觉浅的感觉,很想试试实践的感觉,但是又无从下手。
阅读(753) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~