GCC的优化效果测试
来源:互联网 发布:中华魔力迅白牙膏知乎 编辑:程序博客网 时间:2024/06/04 19:23
有这么个程序:
可以看得出,a + 1 == a在一般情况下是不可能成立的,编译后得到结果:
果然,gcc是知道a不会等于a+1的。于是这激起了我的好奇心,我又想继续为难gcc,于是程序改为:
明显不可能到的分支又被优化掉了,而且这次竟然是跨函数的优化,太强大了!
后来想想,也许是gcc自动把那个很短的函数内联了,才导致被发现并被优化掉,于是程序改成:
编译得到的结果是:
这下明白了,gcc果然是把它内联了才能进行进一步优化。从这里得知内联的好处不仅仅是省去了切换栈帧,更重要的是还可以把两个函数的代码放在一起进行进一步优化。
能不能继续挑战一下gcc?写出如下程序:
很明显,获取了时间t1后,休息3秒,再获取一次时间t2,两次时间一般情况下应该会不同,但是编译出来的结果确是:
#include <stdio.h>int main(int argc, const char *argv[]){int a;scanf("%d", &a);if (a + 1 == a){printf("bad!:(\n");}else{printf("good!:)\n");}return 0;}
可以看得出,a + 1 == a在一般情况下是不可能成立的,编译后得到结果:
.file"deadloop1.c".section.rodata.str1.1,"aMS",@progbits,1.LC0:.string"%d".LC1:.string"good!:)".text.p2align 4,,15.globl main.typemain, @functionmain:pushl%ebpmovl%esp, %ebpandl$-16, %espsubl$32, %espleal28(%esp), %eaxmovl%eax, 4(%esp)movl$.LC0, (%esp)call__isoc99_scanfmovl$.LC1, (%esp)callputsxorl%eax, %eaxleaveret.sizemain, .-main.ident"GCC: (Debian 4.4.5-8) 4.4.5".section.note.GNU-stack,"",@progbits
果然,gcc是知道a不会等于a+1的。于是这激起了我的好奇心,我又想继续为难gcc,于是程序改为:
#include <stdio.h>int inc(int num){return num + 1;}int main(int argc, const char *argv[]){int a;scanf("%d", &a);if (a + 1 == inc(a)){printf("good!:)\n");}else{printf("bad!:(\n");}return 0;}
.file"deadloop.c".text.p2align 4,,15.globl inc.typeinc, @functioninc:pushl%ebpmovl%esp, %ebpmovl8(%ebp), %eaxpopl%ebpaddl$1, %eaxret.sizeinc, .-inc.section.rodata.str1.1,"aMS",@progbits,1.LC0:.string"%d".LC1:.string"good!:)".text.p2align 4,,15.globl main.typemain, @functionmain:pushl%ebpmovl%esp, %ebpandl$-16, %espsubl$32, %espleal28(%esp), %eaxmovl%eax, 4(%esp)movl$.LC0, (%esp)call__isoc99_scanfmovl$.LC1, (%esp)callputsxorl%eax, %eaxleaveret.sizemain, .-main.ident"GCC: (Debian 4.4.5-8) 4.4.5".section.note.GNU-stack,"",@progbits
明显不可能到的分支又被优化掉了,而且这次竟然是跨函数的优化,太强大了!
后来想想,也许是gcc自动把那个很短的函数内联了,才导致被发现并被优化掉,于是程序改成:
#include <stdio.h>int __attribute__((noinline))inc(int num){return num + 1;}int main(int argc, const char *argv[]){int a;scanf("%d", &a);if (a + 1 == inc(a)){printf("good!:)\n");}else{printf("bad!:(\n");}return 0;}
编译得到的结果是:
.file"deadloop.c".text.p2align 4,,15.globl inc.typeinc, @functioninc:pushl%ebpmovl%esp, %ebpmovl8(%ebp), %eaxpopl%ebpaddl$1, %eaxret.sizeinc, .-inc.section.rodata.str1.1,"aMS",@progbits,1.LC0:.string"%d".LC1:.string"good!:)".LC2:.string"bad!:(".text.p2align 4,,15.globl main.typemain, @functionmain:pushl%ebpmovl%esp, %ebpandl$-16, %esppushl%ebxsubl$44, %espleal28(%esp), %eaxmovl%eax, 4(%esp)movl$.LC0, (%esp)call__isoc99_scanfmovl28(%esp), %ebxmovl%ebx, (%esp)addl$1, %ebxcallinccmpl%eax, %ebxje.L8movl$.LC2, (%esp)callputsaddl$44, %espxorl%eax, %eaxpopl%ebxmovl%ebp, %esppopl%ebpret.p2align 4,,7.p2align 3.L8:movl$.LC1, (%esp)callputsaddl$44, %espxorl%eax, %eaxpopl%ebxmovl%ebp, %esppopl%ebpret.sizemain, .-main.ident"GCC: (Debian 4.4.5-8) 4.4.5".section.note.GNU-stack,"",@progbits
这下明白了,gcc果然是把它内联了才能进行进一步优化。从这里得知内联的好处不仅仅是省去了切换栈帧,更重要的是还可以把两个函数的代码放在一起进行进一步优化。
能不能继续挑战一下gcc?写出如下程序:
#include <stdio.h>#include <unistd.h>#include <time.h>int main(int argc, const char *argv[]){time_t t1, t2;time(&t1);sleep(3);time(&t2);if (t1 != t2){printf("good!:)\n");}else{printf("bad!:(\n");}return 0;}
很明显,获取了时间t1后,休息3秒,再获取一次时间t2,两次时间一般情况下应该会不同,但是编译出来的结果确是:
.file"deadloop2.c".section.rodata.str1.1,"aMS",@progbits,1.LC0:.string"good!:)".LC1:.string"bad!:(".text.p2align 4,,15.globl main.typemain, @functionmain:pushl%ebpmovl%esp, %ebpandl$-16, %espsubl$32, %espleal28(%esp), %eaxmovl%eax, (%esp)calltimemovl$3, (%esp)callsleepleal24(%esp), %eaxmovl%eax, (%esp)calltimemovl28(%esp), %eaxcmpl24(%esp), %eaxje.L2movl$.LC0, (%esp)callputsxorl%eax, %eaxleaveret.p2align 4,,7.p2align 3.L2:movl$.LC1, (%esp)callputsxorl%eax, %eaxleaveret.sizemain, .-main.ident"GCC: (Debian 4.4.5-8) 4.4.5".section.note.GNU-stack,"",@progbits
非常遗憾,对于这个逻辑可能是因为调用外部的库或者受这个程序外部因素影响太大,无法再进行优化了。
本次测试用的GCC版本为4.4.5,操作系统为GNU/Linux,优化选项均为-O3。
上面说到的一般情况我是这么理解的,比如a == a并不一定是一个原子操作,就这么简单一个逻辑表达式可能经历的操作是先把a的值从内存放入寄存器1,再把b的值放入寄存器2,再进行比较,其间寄存器和内存的值都有可能被别的进程或线程打断并设法修改。不过很明显,如果连a == a都无法确定,那么编译器的优化手段几乎无从下手了,因为你什么都无法确定。
- GCC的优化效果测试
- GCC的优化效果测试:2
- gcc的优化效果是这样囧么~~
- gcc 的printf() 优化?
- GCC 的优化选项
- gcc的优化选项
- gcc的三级优化
- gcc的三级优化
- 17 一个展示gcc编译优化选项-O效果的实例
- gcc优化导致的错误
- GCC 优化的 strlen() 代码
- gcc 编译的优化选项
- GCC -O 的优化分析
- gcc 的部分优化选项
- GCC对乘法的优化
- gcc优化的简单说明
- GCC优化选项的说明
- gcc三级优化的作用
- 【特别推荐】32套精美的免费 PSD 网页界面设计素材
- 突破产品管理瓶颈---全面产品管理思想概述
- JavaScript学习笔记-- 运算符OPERATORS
- Spring.NET学习笔记4——对象的创建(基础篇) Level 200
- apk的反编译、修改
- GCC的优化效果测试
- github get start
- 使用RICHEDIT
- Libgdx TexturePacker的使用
- linux下编译boost
- 推荐40款强大的 jQuery 导航插件和教程【上篇】
- 为什么析构函数可以为虚函数,什么情况下需要将析构函数定义为虚函数?
- JAVA与JavaScript的同异处总结
- 经典数据结构-块状链表详解