在内核中我们经常遇到likely和unlikely,特别是在出错函数中,那么引入这两个宏有什么作用呢?下面是我在内核include/linux/compiler.h中找到的:
- #define likely(x) __builtin_expect(!!(x), 1)
- #define unlikely(x) __builtin_expect(!!(x), 0)
上述代码的__builtin_expect是GCC提供给程序员使用的,目的是将“分支转移的信息提供给编译器,这样编译器可以对代码进行优化,以减少指令调转带来的性能下降。下面是GCC上__builtin_expect的解释:
- - Built-in Function: long __builtin_expect (long EXP, long C)
- You may use `__builtin_expect' to provide the compiler with branch
- prediction information. In general, you should prefer to use
- actual profile feedback for this (`-fprofile-arcs'), as
- programmers are notoriously bad at predicting how their programs
- actually perform. However, there are applications in which this
- data is hard to collect.
-
- The return value is the value of EXP, which should be an integral
- expression. The value of C must be a compile-time constant. The
- semantics of the built-in are that it is expected that EXP == C.
- For example:
-
- if (__builtin_expect (x, 0))
- foo ();
-
- would indicate that we do not expect to call `foo', since we
- expect `x' to be zero. Since you are limited to integral
- expressions for EXP, you should use constructions such as
-
- if (__builtin_expect (ptr != NULL, 1))
- error ();
-
- when testing pointer or floating-point values.
__builtin_expect(!!(x), 1)表示x为真的可能性大一些。也就是if后面的语句可能性大一些。
__builtin_expect(!!(x), 0)表示x为假的可能性大一些。也就是else后面的语句可能性大一些。
还是用具体的例子解释会更清楚一些:
下面是我在shell底下写的一个C程序:
- lwp@lwp-linux:~/kernel$ cat test2.c
-
- #define LIKELY(x) __builtin_expect(!!(x), 1)
- #define UNLIKELY(x) __builtin_expect(!!(x), 0)
-
- int test_likely(int x)
- {
- if(LIKELY(x))
- {
- x = 5;
- }
- else
- {
- x = 6;
- }
-
- return x;
- }
-
- int test_unlikely(int x)
- {
- if(UNLIKELY(x))
- {
- x = 5;
- }
- else
- {
- x = 6;
- }
-
- return x;
- }
在终端下敲入以下命令:
- lwp@lwp-linux:~/kernel$ gcc -fprofile-arcs -O2 -c test2.c
- lwp@lwp-linux:~/kernel$ objdump -d test2.o
可以得到如下结果:
- test2.o: file format elf32-i386
- Disassembly of section .text:
- 00000000 :
- 0: 83 ec 04 sub $0x4,%esp
- 3: 8b 44 24 08 mov 0x8(%esp),%eax
- 7: 83 05 10 00 00 00 01 addl $0x1,0x10
- e: 83 15 14 00 00 00 00 adcl $0x0,0x14
- 15: 85 c0 test %eax,%eax
- 17: 74 09 je 22
- 19: b8 05 00 00 00 mov $0x5,%eax
- 1e: 83 c4 04 add $0x4,%esp
- 21: c3 ret
- 22: 83 05 18 00 00 00 01 addl $0x1,0x18
- 29: b8 06 00 00 00 mov $0x6,%eax
- 2e: 83 15 1c 00 00 00 00 adcl $0x0,0x1c
- 35: eb e7 jmp 1e
- 37: 89 f6 mov %esi,%esi
- 39: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
- 00000040 :
- 40: 83 ec 04 sub $0x4,%esp
- 43: 8b 54 24 08 mov 0x8(%esp),%edx
- 47: 83 05 00 00 00 00 01 addl $0x1,0x0
- 4e: 83 15 04 00 00 00 00 adcl $0x0,0x4
- 55: 85 d2 test %edx,%edx
- 57: 75 17 jne 70
- 59: 83 05 08 00 00 00 01 addl $0x1,0x8
- 60: b8 06 00 00 00 mov $0x6,%eax
- 65: 83 15 0c 00 00 00 00 adcl $0x0,0xc
- 6c: 83 c4 04 add $0x4,%esp
- 6f: c3 ret
- 70: b8 05 00 00 00 mov $0x5,%eax
- 75: eb f5 jmp 6c
- Disassembly of section .text.startup:
- 00000000 <_GLOBAL__sub_I_65535_0_test_likely>:
- 0: 83 ec 1c sub $0x1c,%esp
- 3: c7 04 24 00 00 00 00 movl $0x0,(%esp)
- a: e8 fc ff ff ff call b <_GLOBAL__sub_I_65535_0_test_likely+0xb>
- f: 83 c4 1c add $0x1c,%esp
- 12: c3 ret
总的来说,这两个宏对程序的结果没有影响,使用它只是提高了程序的效率。我们只有在你已经对可能发生的结果有很大的预算的时候使用它。
阅读(1797) | 评论(0) | 转发(0) |