先看likely与unlikely定义:
include/linux/compiler.h
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
定义在compiler.h说明跟编译器相关,我们来看linux内核编译器GCC的手册里对内建函数__builtin_expect的说明:
long __builtin_expect (long exp, long c) [Built-in Function]
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
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))
foo (*ptr);
when testing pointer or floating-point values.
GCC提供这个内建函数来帮助处理分子预测,优化程序。编译器根据表达式exp的预期值c来适当地重排条件语句块的顺序,将适合这个条件的分支放在合适的地方。
unlikely(x)告诉编译器x发生的可能性不大,那么这个条件语句块的目标码就会放在一个比较远的位置,而另一分支的语句块的目标码则放在前面的代码对应的目标码的后面,这样运行可能性大的代码放的比较紧凑;likely(x)则相反。大家可以写一小段代码,反汇编来验证下。
此处应该有疑问,为啥目标码紧凑效率就高呢?
那是因为现代处理器都是流水线的,系统可以按顺序预取指令,但遇到跳转时,相当于要重新预取指令,就降低了速度。
在可能性比较大的条件判断加likely(),反之加unlikely(),这样编译器会将可能性大的分支语句块紧跟在前面的代码后面,运行时就会减少指令跳转带来的性能下降。
include/linux/compiler.h
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
定义在compiler.h说明跟编译器相关,我们来看linux内核编译器GCC的手册里对内建函数__builtin_expect的说明:
long __builtin_expect (long exp, long c) [Built-in Function]
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
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))
foo (*ptr);
when testing pointer or floating-point values.
GCC提供这个内建函数来帮助处理分子预测,优化程序。编译器根据表达式exp的预期值c来适当地重排条件语句块的顺序,将适合这个条件的分支放在合适的地方。
unlikely(x)告诉编译器x发生的可能性不大,那么这个条件语句块的目标码就会放在一个比较远的位置,而另一分支的语句块的目标码则放在前面的代码对应的目标码的后面,这样运行可能性大的代码放的比较紧凑;likely(x)则相反。大家可以写一小段代码,反汇编来验证下。
此处应该有疑问,为啥目标码紧凑效率就高呢?
那是因为现代处理器都是流水线的,系统可以按顺序预取指令,但遇到跳转时,相当于要重新预取指令,就降低了速度。
在可能性比较大的条件判断加likely(),反之加unlikely(),这样编译器会将可能性大的分支语句块紧跟在前面的代码后面,运行时就会减少指令跳转带来的性能下降。