日期:2014-05-16  浏览次数:20723 次

linux内核中的likely和unlikely

linux内核中的likely和unlikely

Kernel version:2.6.14

CPU architecture:ARM920T

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

GCC version:arm-linux-gcc-3.4.1

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

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

下面详细分析一下。

likely() 与 unlikely()是内核中定义的两个宏。位于/include/linux/compiler.h中,具体定义如下:

#define likely(x)	__builtin_expect(!!(x), 1)
#define unlikely(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为一个编译期常量,这个函