使用likely和unlikely 优化程序性能

2018-11-14  本文已影响0人  wywindz

作用

likely unlikely是为编译器提供对分支优化的提示,基本用于if-else的分支优化场景。if-else在汇编时会将else分支的命令生成跳转语句(jmp),而跳转会影响程序性能,所以如果大部分情况下都是else分支成立的话,程序每次都会执行跳转,从而影响效率,使用likelyunlikely即可以告诉编译器大部分情况下哪个分支更有可能成立,从而将该分支的语句编译到前面,提高运行效率。

实现

likelyunlikely是通过宏定义实现的:

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

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.

使用

举个栗子🌰

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

int main(char *argv[], int argc)
{
   int a;

   /* Get the value from somewhere GCC can't optimize */
   a = atoi (argv[1]);

   if (unlikely (a == 2)) //等同于if(a==2)
      a++;
   else
      a--;

   printf ("%d\n", a);

   return 0;
}

注意,编译时需要加 -O2选项
可以用objdump -S XXX 来查看汇编指令
使用unlikely()时,汇编指令为je(相等则跳转)
而使用likely()时,汇编指令为jne (不相等则跳转)

上一篇下一篇

猜你喜欢

热点阅读