Chinaunix首页 | 论坛 | 博客
  • 博客访问: 378220
  • 博文数量: 47
  • 博客积分: 967
  • 博客等级: 准尉
  • 技术积分: 1290
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-25 16:14
文章分类

全部博文(47)

文章存档

2019年(1)

2014年(1)

2013年(9)

2012年(36)

分类: LINUX

2012-06-24 11:58:58

   在内核中我们经常遇到likely和unlikely,特别是在出错函数中,那么引入这两个宏有什么作用呢?下面是我在内核include/linux/compiler.h中找到的:

   

点击(此处)折叠或打开

  1. #define likely(x) __builtin_expect(!!(x), 1)
  2. #define unlikely(x) __builtin_expect(!!(x), 0)

  上述代码的__builtin_expect是GCC提供给程序员使用的,目的是将“分支转移的信息提供给编译器,这样编译器可以对代码进行优化,以减少指令调转带来的性能下降。下面是GCC上__builtin_expect的解释:
  

点击(此处)折叠或打开

  1. - Built-in Function: long __builtin_expect (long EXP, long C)
  2.      You may use `__builtin_expect' to provide the compiler with branch
  3.      prediction information. In general, you should prefer to use
  4.      actual profile feedback for this (`-fprofile-arcs'), as
  5.      programmers are notoriously bad at predicting how their programs
  6.      actually perform. However, there are applications in which this
  7.      data is hard to collect.
  8.                                                                    
  9.      The return value is the value of EXP, which should be an integral
  10.      expression. The value of C must be a compile-time constant. The
  11.      semantics of the built-in are that it is expected that EXP == C.
  12.      For example:
  13.                                                                    
  14.           if (__builtin_expect (x, 0))
  15.             foo ();
  16.                                                                    
  17.      would indicate that we do not expect to call `foo', since we
  18.      expect `x' to be zero. Since you are limited to integral
  19.      expressions for EXP, you should use constructions such as
  20.                                                                    
  21.           if (__builtin_expect (ptr != NULL, 1))
  22.             error ();
  23.                                                                    
  24.      when testing pointer or floating-point values.

 __builtin_expect(!!(x), 1)表示x为真的可能性大一些。也就是if后面的语句可能性大一些。

 __builtin_expect(!!(x), 0)表示x为假的可能性大一些。也就是else后面的语句可能性大一些。

 还是用具体的例子解释会更清楚一些:

下面是我在shell底下写的一个C程序:  

点击(此处)折叠或打开

  1. lwp@lwp-linux:~/kernel$ cat test2.c
  2.                                               
  3. #define LIKELY(x) __builtin_expect(!!(x), 1)
  4. #define UNLIKELY(x) __builtin_expect(!!(x), 0)
  5.                                              
  6. int test_likely(int x)
  7. {
  8.  if(LIKELY(x))
  9.  {
  10.     x = 5;
  11.  }
  12.  else
  13.  {
  14.     x = 6;
  15.  }
  16.                                                
  17.  return x;
  18. }
  19.                                              
  20. int test_unlikely(int x)
  21. {
  22.  if(UNLIKELY(x))
  23.  {
  24.     x = 5;
  25.  }
  26.  else
  27.  {
  28.     x = 6;
  29.  }
  30.                                                
  31.  return x;
  32. }

在终端下敲入以下命令:

点击(此处)折叠或打开

  1. lwp@lwp-linux:~/kernel$ gcc -fprofile-arcs -O2 -c test2.c
  2. lwp@lwp-linux:~/kernel$ objdump -d test2.o

可以得到如下结果:


点击(此处)折叠或打开

  1. test2.o: file format elf32-i386
  2. Disassembly of section .text:
  3. 00000000 :
  4. 0: 83 ec 04 sub $0x4,%esp
  5. 3: 8b 44 24 08 mov 0x8(%esp),%eax
  6. 7: 83 05 10 00 00 00 01 addl $0x1,0x10
  7. e: 83 15 14 00 00 00 00 adcl $0x0,0x14
  8. 15: 85 c0 test %eax,%eax
  9. 17: 74 09 je 22
  10. 19: b8 05 00 00 00 mov $0x5,%eax
  11. 1e: 83 c4 04 add $0x4,%esp
  12. 21: c3 ret
  13. 22: 83 05 18 00 00 00 01 addl $0x1,0x18
  14. 29: b8 06 00 00 00 mov $0x6,%eax
  15. 2e: 83 15 1c 00 00 00 00 adcl $0x0,0x1c
  16. 35: eb e7 jmp 1e
  17. 37: 89 f6 mov %esi,%esi
  18. 39: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
  19. 00000040 :
  20. 40: 83 ec 04 sub $0x4,%esp
  21. 43: 8b 54 24 08 mov 0x8(%esp),%edx
  22. 47: 83 05 00 00 00 00 01 addl $0x1,0x0
  23. 4e: 83 15 04 00 00 00 00 adcl $0x0,0x4
  24. 55: 85 d2 test %edx,%edx
  25. 57: 75 17 jne 70
  26. 59: 83 05 08 00 00 00 01 addl $0x1,0x8
  27. 60: b8 06 00 00 00 mov $0x6,%eax
  28. 65: 83 15 0c 00 00 00 00 adcl $0x0,0xc
  29. 6c: 83 c4 04 add $0x4,%esp
  30. 6f: c3 ret
  31. 70: b8 05 00 00 00 mov $0x5,%eax
  32. 75: eb f5 jmp 6c
  33. Disassembly of section .text.startup:
  34. 00000000 <_GLOBAL__sub_I_65535_0_test_likely>:
  35. 0: 83 ec 1c sub $0x1c,%esp
  36. 3: c7 04 24 00 00 00 00 movl $0x0,(%esp)
  37. a: e8 fc ff ff ff call b <_GLOBAL__sub_I_65535_0_test_likely+0xb>
  38. f: 83 c4 1c add $0x1c,%esp
  39. 12: c3 ret

    总的来说,这两个宏对程序的结果没有影响,使用它只是提高了程序的效率。我们只有在你已经对可能发生的结果有很大的预算的时候使用它。

阅读(1797) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~