< Linux Kernel > Compile-Time Optimization for Condition Checks

本文介绍Linux内核中likely与unlikely宏的应用,这两种宏利用gcc编译器特性优化代码执行路径,提升性能。通过实例说明如何预测条件分支结果,减少不必要的指令跳转。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Most of the time, when the kernel compares a variable against some external value to see
whether a given condition is met, the result is extremely likely to be predictable. This is
pretty common, for example, with code that enforces sanity checks. The kernel uses the
likely and unlikely macros, respectively, to wrap comparisons that are likely to return
a true (1) or false (0) result. Those macros take advantage of a feature of the gcc compiler

that can optimize the compilation of the code based on that information.


Here is an example. Let's suppose you need to call the do_something function, and that

in case of failure, you must handle it with the handle_error function:


err = do_something(x,y,z);
if (err)

      handle_error(err);


   Under the assumption that do_something rarely fails, you can rewrite the code as
follows:

err = do_something(x,y,z);

if (unlikely(err))

      handle_error(err);


An example of the optimization made possible by the likely and unlikely macros is in
handling options in the IP header. The use of IP options is limited to very specific cases, and
the kernel can safely assume that most IP packets do not carry IP options. When the kernel
forwards an IP packet, it needs to take care of options according to the rules described in
Chapter 18. The last stage of forwarding an IP packet is taken care of by
ip_forward_finish. This function uses the unlikely macro to wrap the condition
that checks whether there is any IP option to take care of. See the section "ip_forward_finish
Function" in Chapter 20.


http://blog.youkuaiyun.com/tigerjibo/article/details/8279183


likely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢?

首先明确:

if (likely(value))等价于if (value)
if (likely(a>b)) {
fun1();

if (unlikely(value))等价于if (value)

也就是说likely()和unlikely()从阅读和理解的角度是一样的。

这两个宏在内核中定义如下:
  1. <linux/compiler>

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

  3. #define unlikely(x) __builtin_expect(!!(x), 0)

这里的__built_expect()函数是gcc(version >= 2.96)的内建函数,提供给程序员使用的,目的是将"分支转移"的信

息提供给编译器,这样编译器对代码进行优化,以减少指令跳转带来的性能下降。

__buildin_expect((x), 1)表示x的值为真的可能性更大。

__buildin_expect((x), 0)表示x的值为假的可能性更大。

也就是说,使用likely(),执行if后面的语句的机会更大,使用unlikely(),执行else后面的语句机会更大一些。通过这种

方式,编译器在编译过程中,会将可能性更大的代码紧跟着后面的代码,从而减少指令跳转带来的性能上的下降。

比如 :
  1. if (likely(a>b)) {

  2. fun1();

  3. }

这里就是程序员可以确定 a>b 在程序执行流程中出现的可能相比较大,因此运用了likely()告诉编译器将fun1()函数

的二进制代码紧跟在前面程序的后面,这样就cache在预取数据时就可以将fun1()函数的二进制代码拿到cache中。

这样,也就添加了cache的命中率。

同样的,unlikely()的作用就是告诉编译器,a<b 的可能性很小所以这里在编译时,将fun2()的二进制代码尽量

不要和前边的编译在一块。咱们不用对likely和unlikely感到迷惑,须要知晓的就是 if(likely(a>b)) 和 if(a>b)在功能

上是等价的,同样 if(unlikely(a<b)) 和 if(a<b) 的功能也是一样的。不一样的只是他们声称的二进制代码有所不一

样,这一点咱们也可以从他们的汇编代码中看到。总之,likely和unlikely的功能就是添加 cache的命中率,提高系统

执行速度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值