本文主要是介绍[笔记]CSAPP第五章 优化程序性能,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
第四章与CPU设计有关,暂时跳过,以后有时间再看。
- 编写高效程序要点:
- 必须选择一组合适的算法和数据结构;
- 必须编写出编译器能够有效优化以转换成高效可执行代码的源代码;
- 针对运算量特别大的计算,将一个任务分成多个部分,在多核和多处理器的某种组合上并行地计算。(第12章内容)
优化编译器的能力和局限性
程序性能表示方式
- CPE:Cycles Per Element,每元素的周期数。用时钟周期而不是具体时间来表示程序的性能。
提高性能的几种方法
消除循环的低效率
- 循环内要执行多次但是计算结果不会改变的计算,应该从循环内部移动到循环前。
- 有些结果不变的计算可能复杂度较高,并且处于函数内部,编译器难以进行优化,需要程序员手动优化。
减少过程调用
- 过程调用会带来开销,并且妨碍大多数形式的程序优化。
消除不必要的内存引用
- 引入临时变量来存储对某个指针的值,在之后的操作中改变临时变量的值,最后将临时变量的值写入指针,可以将对内存的访问转换为寄存器操作,提高程序性能。(访问寄存器比访问内存快得多)
循环展开
- 通过增加每一次迭代计算的元素数量,减少循环的迭代次数。(编译器可以很容易地执行循环展开)
提高并行性
- 对于一个可结合和可交换的合并运算来说,可以通过将一组合并运算分割成两个或多个部分,并在最后合并结果来提高性能。
- 合适的重新组合变换能够减少计算中关键路径上操作的数量,通过更好地利用功能单元的流水线能力得到更好的性能。
一些限制因素
理解内存性能
- 加载(从内存读到寄存器)和存储(从寄存器写到内存)。
加载的性能
- 包含加载操作的程序的性能既依赖于流水线的能力,也依赖于加载单元的延迟。
存储的性能
-
存储操作不影响任何寄存器值。
-
考虑下面两个调用A和B,A的CPE比B的CPE小,这是因为A中从*src
读出的结果不受对*dest
的写的影响,而B中存在参数src
和dest
都是指向数组元素a[0]
的指针,这时指针引用*src
的每次加载都会得到指针引用*dest
的上一次执行存储的值。这就是写/读相关:一个内存读的结果依赖于一个最近的内存写。
/* Write to dest , read from src */
void write_read(long *src, long *dst, long n)
{
long cnt = n;
long val = 0;
while (cnt) {
*dst = val ;
val = (*src) + 1;
cnt--;
}
}
//example A
write_read(&a[0], &a[1], 3);
//example B
write_read(&a[0], &a[0], 3);
这篇关于[笔记]CSAPP第五章 优化程序性能的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!