最近看了《深入理解计算机系统》这本书,对其中程序优化这一章节进行了深入学习,以此博客作为学习记录。
先总结几点程序优化的原则:
1. 代码正确问题,一个运行很快但是给出了错误结果的程序没有任何用处
2. 代码清晰简洁,这样不仅是为了自己看懂代码,也是为了检查代码和今后需要修改时,其他人能够读懂和理解代码
3. 考虑代码的使用方式和影响它的关键因素,低级别的代码优化没有带来较大的性能提高反而使得程序的可读性和拓展性下降,更容易出错了,这就不是一个理想的代码优化。我们应当选择那些性能重要的环境下反复执行的代码进行大量的优化。
程序高效程序可以从以下几个方向出发:
1、 选择一组适当的算法和数据结构。
2、 编写出编译器能有效转化成高效可执行代码的源代码。这对理解优化编译器的能力和局限性要求比较高
优化编译器的能力和局限性。
了解编译系统如何工作是大有益处的;
1、优化程序性能。(为了我们在C程序中做出好的代码选择我们确实需要对汇编语言以及编译器如何将不同的C语句转化为汇编语言有一些基本的了解)
2、理解连接时出现的错误。(一些最令人困扰的程序错误往往都与链接器操作有关,尤其是当你试图建立大型的软件系统时)
3、避免安全漏洞。(近年来,缓冲区溢出错误造成大多数网络和Internet服务器上的安全漏洞,这些而错误的存在时因为太多的程序员忽视了编译器用来为函数产生代码的堆栈规则)
首先在学习控制之前先要了解编译器,现代编译器运用复杂精细的算法来确定一个程序的计算值,以及它们是如何被使用的,大多数编译包括GCC向用户提供了一些对它们所使用的优化的控制。最简单的控制就是指定优化级别,例如用命令“-Og”调用GCC就是让GCC只做基本的优化,而-O1或者更好的优化级别都是可以支持的。虽然对于大多数GCC软件项目来说-O2已经成为了可以被接收的标准,但是主要还是考虑以优化级别为-O1编译出的代码。在以此为基础下,我们做了接下来的对比测试。
举一个简单的例子,考虑以下代码
void test1(long *xp,long *yp)
{
*xp+= *yp;
*xp+= *yp;
}
void test2(long *xp,long *yp)
{
*xp+= *yp * 2;
}
我们能知道test1,使用6次内存读写,而test2只用了三次内存读写,因为我们会以为test1会优化为test2版本,然而实际上并没有,考虑到当xp=yp的时候,test1计算结果了4倍*xp,而test2只计算出3倍*xp,而编译器在编译时不知道该函数会被如何调用故不会产生test2的优化。
(结论:在只执行安全的优化中,编译器必须假设不同的指针可能指向同一位置)
函数调用会妨碍优化,考虑以下代码
long