您的位置 首页 ADAS

linux内核中的likely和unlikely

Kernelversion:2614CPUarchitecture:ARM920TAuthor:ce123(http:blogcsdnnetce123)GCCversion:arm-linux-gcc

Kernel version:2.6.14

CPU architecture:ARM920T

Author:ce123(http://blog.csdn.net/ce123)

GCCversion:arm-linux-gcc-3.4.1

看内核时常常遇到if(likely( )){}或是if(unlikely( ))这样的句子,不甚了解,例如(选自kernel/fork.c中copy_process):

[plain]view plaincopy

print?

  1. SET_LINKS(p);
  2. if(unlikely(p->ptrace&PT_PTRACED))
  3. __ptrace_link(p,current->parent);

下面详细剖析一下。

likely() 与 unlikely()是内核中界说的两个宏。坐落/include/linux/compiler.h中,详细界说如下:

[plain]view plaincopy

print?

  1. #definelikely(x)__builtin_expect(!!(x),1)
  2. #defineunlikely(x)__builtin_expect(!!(x),0)

__builtin_expect是GCC(version>=2.9)引入的内建函数,其效果便是协助编译器判别条件跳转的预期值,防止跳转形成时刻乱费,有利于代码优化。查阅GCC手册,发现其界说如下(http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html):

— 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.

大致意思是:能够运用。由于大部分程序员在分支猜测方面做得很糟糕,所以GCC供给了__builtin_expect这个内建函数,给编译器供给分支猜测信息,以协助程序员处理分支猜测,优化程序。其第一个参数EXP为一个整型表达式,这个内建函数的回来值也是这个EXP,而C为一个编译期常量,这个函数的语义是:你希望EXP表达式的值等于常量C,然后GCC为你优化程序,将契合这个条件的分支放在适宜的当地。由于该内建函数只供给了整型表达式,所以假如你要优化其他类型的表达式,能够选用指针的方式。

当GCC的版别较低时(_GNUC_MINOR__ < 96),__builtin_expect直接回来EXP。下面的代码摘自/include/linux/compiler-gcc2.h。

[plain]view plaincopy

print?

  1. /*ThesedefinitionsareforGCCv2.x.*/
  2. /*SomewhereinthemiddleoftheGCC2.96developmentcycle,weimplemented
  3. amechanismbywhichtheusercanannotatelikelybranchdirectionsand
  4. expecttheblockstobereorderedappropriately.Define__builtin_expect
  5. tonothingforearliercompilers.*/
  6. #include
  7. #if__GNUC_MINOR__<96
  8. #define__builtin_expect(x,expected_value)(x)
  9. #endif

总结一下:if() 句子照常用, 和曾经相同, 仅仅 假如你觉得if()是1 的可能性十分大的时分, 就在表达式的外面加一个likely(),假如可能性十分小(比方几率十分小),就用unlikely()包裹上。下面咱们看一个比如。

[plain]view plaincopy

print?

  1. //test_builtin_expect.c
  2. #definelikely(x)__builtin_expect(!!(x),1)
  3. #defineunlikely(x)__builtin_expect(!!(x),0)
  4. inttest_likely(intx)
  5. {
  6. if(likely(x))
  7. x=5;
  8. else
  9. x=6;
  10. returnx;
  11. }
  12. inttest_unlikely(intx)
  13. {
  14. if(unlikely(x))
  15. x=5;
  16. else
  17. x=6;
  18. returnx;
  19. }

root@czu:~/桌面/socket# arm-linux-gcc -fprofile-arcs -O2 -c test.c

root@czu:~/桌面/socket# arm-linux-gcc -fprofile-arcs -O2 -o test test.c

root@czu:~/桌面/socket# arm-linux-objdump -D test > test.dis

[plain]view plaincopy

print?

  1. 000088cc:
  2. 88cc:e3500000cmpr0,#0;0x0
  3. 88d0:e92d4010stmdbsp!,{r4,lr}
  4. 88d4:e59fc044ldrip,[pc,#68];8920<.text+0x148>
  5. 88d8:e59fe044ldrlr,[pc,#68];8924<.text+0x14c>
  6. 88dc:e3a00005movr0,#5;0x5
  7. 88e0:0a000006beq8900//前面经过cmp将r0和0进行比较,由于x=1的概率很大,优先履行不等于0的分支
  8. 88e4:e89c0018ldmiaip,{r3,r4}
  9. 88e8:e3a02000movr2,#0;0x0
  10. 88ec:e3a01001movr1,#1;0x1
  11. 88f0:e0933001addsr3,r3,r1
  12. 88f4:e0a44002adcr4,r4,r2
  13. 88f8:e88c0018stmiaip,{r3,r4}
  14. 88fc:e8bd8010ldmiasp!,{r4,pc}
  15. 8900:e89e0006ldmialr,{r1,r2}
  16. 8904:e3a04000movr4,#0;0x0
  17. 8908:e3a03001movr3,#1;0x1
  18. 890c:e0911003addsr1,r1,r3
  19. 8910:e0a22004adcr2,r2,r4
  20. 8914:e3a00006movr0,#6;0x6
  21. 8918:e88e0006stmialr,{r1,r2}
  22. 891c:e8bd8010ldmiasp!,{r4,pc}
  23. 8920:000121e0andeqr2,r1,r0,ror#3
  24. 8924:000121e8andeqr2,r1,r8,ror#3
  25. 00008928:
  26. 8928:e3500000cmpr0,#0;0x0
  27. 892c:e92d4010stmdbsp!,{r4,lr}
  28. 8930:e59fc044ldrip,[pc,#68];897c<.text+0x1a4>
  29. 8934:e59fe044ldrlr,[pc,#68];8980<.text+0x1a8>
  30. 8938:e3a00005movr0,#5;0x5
  31. 893c:1a000007bne8960//前面经过cmp将r0和0进行比较,由于x=0的概率很大,优先履行等于0的分支
  32. 8940:e89c0018ldmiaip,{r3,r4}
  33. 8944:e3a02000movr2,#0;0x0
  34. 8948:e3a01001movr1,#1;0x1
  35. 894c:e0933001addsr3,r3,r1
  36. 8950:e0a44002adcr4,r4,r2
  37. 8954:e3a00006movr0,#6;0x6
  38. 8958:e88c0018stmiaip,{r3,r4}
  39. 895c:e8bd8010ldmiasp!,{r4,pc}
  40. 8960:e89e0006ldmialr,{r1,r2}
  41. 8964:e3a04000movr4,#0;0x0
  42. 8968:e3a03001movr3,#1;0x1
  43. 896c:e0911003addsr1,r1,r3
  44. 8970:e0a22004adcr2,r2,r4
  45. 8974:e88e0006stmialr,{r1,r2}
  46. 8978:e8bd8010ldmiasp!,{r4,pc}
  47. 897c:000121f8streqdr2,[r1],-r8
  48. 8980:000121f0streqdr2,[r1],-r0

假如咱们将代码修正一下,不必这两个宏成果会怎样呢?

[plain]view plaincopy

print?

  1. //test_builtin_expect.c
  2. inttest_likely(intx)
  3. {
  4. if(x)
  5. x=5;
  6. else
  7. x=6;
  8. returnx;
  9. }
  10. inttest_unlikely(intx)
  11. {
  12. if(x)
  13. x=5;
  14. else
  15. x=6;
  16. returnx;
  17. }

反汇编代码如下:

[plain]view plaincopy

print?

  1. 00008460:
  2. 8460:e3500000cmpr0,#0;0x0
  3. 8464:03a00006moveqr0,#6;0x6
  4. 8468:13a00005movner0,#5;0x5
  5. 846c:e1a0f00emovpc,lr
  6. 00008470:
  7. 8470:e3500000cmpr0,#0;0x0
  8. 8474:03a00006moveqr0,#6;0x6
  9. 8478:13a00005movner0,#5;0x5
  10. 847c:e1a0f00emovpc,lr

如上述比如剖析所示,两个函数编译生成的汇编句子所运用到的跳转指令不相同,仔细剖析下会发现__builtin_expect实际上是为了满意在大大都状况不履行跳转指令,__builtin_expect仅仅是告知编译器优化,并没有改动其对真值的判别。宏likely和宏unlikely仅有的效果便是挑选”将if分支仍是else分支放在跳转指令之后,然后优化程序的履行功率”。 由于likely(EXP)代表条件表达式EXP很可能建立,而unlikely(EXP)代表条件表达式EXP很可能不建立,当程序员清楚EXP表达式 大都状况建立(不建立)时,就可运用likely(unlikely),使if分支(else分支)紧跟跳转指令这以后,然后在大大都状况下不必履行跳转指令,避开跳转指令所带来的开支,然后到达优化的意图。

还有一点需求留意的是,在生成汇编时用的是arm-linux-gcc -fprofile-arcs -O2 -c test_builtin_expect.c,而不是arm-linux-gcc-O2 -c test_builtin_expect.c。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qiche/adas/262416.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部