浅析linux中unlikely即__builtin_expect编译宏的实际意义所在
luther@gliethttp:~$ man gcc 可以查看-fno-builtin-function
luther@gliethttp:~$ gcc -g builtin_expect_func.c
luther@gliethttp:~$ ./a.out
else
if
if
else
if
if
所以这里可以看到if(__builtin_expect(cmd, 0))在逻辑上等效if(cmd).
luther@gliethttp:~$ objdump -DS a.out |tee luther.c 或者使用gdb或insight调试
...
08048406 <builtin_expect_func1>:
char* builtin_expect_func1(int cmd)
{
8048406: 55 push %ebp
8048407: 89 e5 mov %esp,%ebp
8048409: 83 ec 04 sub $0x4,%esp
if(__builtin_expect(cmd, 0)) {
804840c: 8b 45 08 mov 0x8(%ebp),%eax
804840f: 85 c0 test %eax,%eax
8048411: 74 09 je 804841c <builtin_expect_func1+0x16>
return "if";
8048413: c7 45 fc 10 85 04 08 movl $0x8048510,-0x4(%ebp)
804841a: eb 07 jmp 8048423 <builtin_expect_func1+0x1d>
} else {
return "else";
804841c: c7 45 fc 13 85 04 08 movl $0x8048513,-0x4(%ebp)
8048423: 8b 45 fc mov -0x4(%ebp),%eax
}
}
8048426: c9 leave
8048427: c3 ret
08048428 <builtin_expect_func2>:
char* builtin_expect_func2(int cmd)
{
8048428: 55 push %ebp
8048429: 89 e5 mov %esp,%ebp
804842b: 83 ec 04 sub $0x4,%esp
if(__builtin_expect(cmd, 1)) {
804842e: 8b 45 08 mov 0x8(%ebp),%eax
8048431: 85 c0 test %eax,%eax
8048433: 74 09 je 804843e <builtin_expect_func2+0x16>
return "if";
8048435: c7 45 fc 10 85 04 08 movl $0x8048510,-0x4(%ebp)
804843c: eb 07 jmp 8048445 <builtin_expect_func2+0x1d>
} else {
return "else";
804843e: c7 45 fc 13 85 04 08 movl $0x8048513,-0x4(%ebp)
8048445: 8b 45 fc mov -0x4(%ebp),%eax
}
}
8048448: c9 leave
8048449: c3 ret
...
可以看到并没有什么影响,与直接使用if(cmd)没有任何区别
luther@gliethttp:~$ man gcc 可以查看-fno-builtin-function
luther@gliethttp:~$ gcc -g -O2 builtin_expect_func.c 进行-O2优化或者-O3优化
luther@gliethttp:~$ ./a.out
else
if
if
else
if
if
所以这里可以看到在-O2最大优化,if(__builtin_expect(cmd, 0))在逻辑上仍等效if(cmd).
luther@gliethttp:~$ objdump -DS a.out |tee luther.c 或者使用gdb或insight调试
...
char* builtin_expect_func2(int cmd)
{
8048380: 55 push %ebp
if(__builtin_expect(cmd, 1)) {
8048381: b8 20 85 04 08 mov $0x8048520,%eax
return "else";
}
}
char* builtin_expect_func2(int cmd)
{
8048386: 89 e5 mov %esp,%ebp
if(__builtin_expect(cmd, 1)) {
8048388: 8b 55 08 mov 0x8(%ebp),%edx
804838b: 85 d2 test %edx,%edx
804838d: 74 02 je 8048391 <builtin_expect_func2+0x11> //可以看到这里跳转为je表示等于0的话跳,所以优先考虑1-if,这样可以减少一个跳转指令的执行,,如果cmd等于1的几率非常高,那么可以很好的完成优化,减少很多跳转[luther.gliethttp]
return "if";
} else {
return "else";
}
}
804838f: 5d pop %ebp
8048390: c3 ret
8048391: 5d pop %ebp
}
}
char* builtin_expect_func2(int cmd)
{
if(__builtin_expect(cmd, 1)) {
8048392: b8 23 85 04 08 mov $0x8048523,%eax
return "if";
} else {
return "else";
}
}
8048397: c3 ret
8048398: 90 nop
8048399: 8d b4 26 00 00 00 00 lea 0x0(%esi),%esi
080483a0 <builtin_expect_func1>:
printf("%s\n",builtin_expect_func2(2));
}
char* builtin_expect_func1(int cmd)
{
80483a0: 55 push %ebp
if(__builtin_expect(cmd, 0)) {
80483a1: b8 20 85 04 08 mov $0x8048520,%eax
printf("%s\n",builtin_expect_func2(2));
}
char* builtin_expect_func1(int cmd)
{
80483a6: 89 e5 mov %esp,%ebp
if(__builtin_expect(cmd, 0)) {
80483a8: 8b 4d 08 mov 0x8(%ebp),%ecx
80483ab: 85 c9 test %ecx,%ecx
80483ad: 75 05 jne 80483b4 <builtin_expect_func1+0x14>//可以看到这里跳转为jne,非0,所以优先考虑0-if,这样可以减少一个跳转指令的执行,如果cmd等于0的几率非常高,那么可以很好的完成优化,减少很多跳转[luther.gliethttp]
80483af: b8 23 85 04 08 mov $0x8048523,%eax
return "if";
} else {
return "else";
}
}
80483b4: 5d pop %ebp
80483b5: c3 ret
...
测试源码:
#include <stdio.h>
char* builtin_expect_func1(int cmd);
char* builtin_expect_func2(int cmd);
int main(int argc, char *argv[])
{
printf("%s\n",builtin_expect_func1(0));
printf("%s\n",builtin_expect_func1(1));
printf("%s\n",builtin_expect_func1(2));
printf("%s\n",builtin_expect_func2(0));
printf("%s\n",builtin_expect_func2(1));
printf("%s\n",builtin_expect_func2(2));
}
char* builtin_expect_func1(int cmd)
{
if(__builtin_expect(cmd, 0)) {
return "if";
} else {
return "else";
}
}
char* builtin_expect_func2(int cmd)
{
if(__builtin_expect(cmd, 1)) {
return "if";
} else {
return "else";
}
}
|