likely() | unlikely()

在内核代码中常见到两个宏 likely() 和 unlikly() ,它们定义在 include/linux/compiler.h 中:
引用
#define likely(x)    __builtin_expect(!!(x), 1)
#define unlikely(x)    __builtin_expect(!!(x), 0)

__builtin_expect 是 gcc 的内置函数,它的原型为 long __builtin_expect (long exp, long c) ,第 1 个参数可以是个整数,也可以是个布尔型表达式,函数的返回值为 exp 。使用 __builtin_expect 可以为编译器提供跳转预测信息,关于跳转预测相关内容可参考: http://www.groad.net/bbs/read.php?tid-1455-fpage-3.html http://www.groad.net/bbs/read.php?tid-1456-fpage-3.html


该函数的意思是,期望 " exp == c " 。因此,


__builtin_expect(!!(x), 1) 表示 !!(x) 为真的可能性很大,如果 !!(x) 确实为真,那么整个函数的返回值为真。
__builtin_expect(!!(x), 0) 表示 !!(x) 为假的可能性很大,如果 !!(x) 确实为假,那么整个函数的返回值为假。



注意,上面的可能性是程序员所“认为”的,但实际情况不一定就是真或假,然而编译器会按照你所认为的 “可能性” 去安排跳转预测。


下面通过测试程序来验证:

#include <stdio.h>

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

void test_like (int x)
{

        if (unlikely(x))
                x = x + 8;

        else
                x = x + 10;


        printf ("x = %d\n", x);
}

int main(void)
{

        test_like (10);
        return (0);
}


编译
引用
gcc -O2 builtin_expect.c -o builtin_expect

反汇编

08048430 <test_like>:
8048430:       55                      push   %ebp
8048431:       89 e5                   mov    %esp,%ebp
8048433:       83 ec 18                sub    $0x18,%esp
8048436:       8b 45 08                mov    0x8(%ebp),%eax
8048439:       85 c0                   test   %eax,%eax
804843b:       75 17                   jne    8048454 <test_like+0x24>
804843d:       b8 0a 00 00 00          mov    $0xa,%eax       /* x = x + 10; */
8048442:       89 44 24 04             mov    %eax,0x4(%esp)
8048446:       c7 04 24 50 85 04 08    movl   $0x8048550,(%esp)
804844d:       e8 02 ff ff ff          call   8048354 <printf@plt>
8048452:       c9                      leave  

8048453:       c3                      ret    
8048454:       83 c0 08                add    $0x8,%eax             /* x = x + 8 */
8048457:       eb e9                   jmp    8048442 <test_like+0x12>
8048459:       8d b4 26 00 00 00 00    lea    0x0(%esi,%eiz,1),%esi


将上面程序中的 test_like(10) 中的 10 改为 0 再看反汇编

08048430 <test_like>:
8048430:       55                      push   %ebp
8048431:       89 e5                   mov    %esp,%ebp
8048433:       83 ec 18                sub    $0x18,%esp
8048436:       8b 45 08                mov    0x8(%ebp),%eax
8048439:       85 c0                   test   %eax,%eax
804843b:       75 17                   jne    8048454 <test_like+0x24>
804843d:       b8 0a 00 00 00          mov    $0xa,%eax
8048442:       89 44 24 04             mov    %eax,0x4(%esp)
8048446:       c7 04 24 50 85 04 08    movl   $0x8048550,(%esp)
804844d:       e8 02 ff ff ff          call   8048354 <printf@plt>
8048452:       c9                      leave  
8048453:       c3                      ret    
8048454:       83 c0 08                add    $0x8,%eax
8048457:       eb e9                   jmp    8048442 <test_like+0x12>
8048459:       8d b4 26 00 00 00 00    lea    0x0(%esi,%eiz,1),%esi



从上面可以看到两个反汇编的内容一样,也就是说不管传递的参数是真或是假,程序跳转预测的安排都只是根据 __builtin_expect 来安排。
因为 unlikely() 是条件很可能为假,那么也就是要执行 x = x + 10 这条语句,所以编译器不安排跳转。从指令缓存的角度来看,跳转很可能是跳转到缓存之外的,这样会减慢程序的执行速度。
同样可以测试 likely() 的情况。
另外需要注意一点区别,unlikely() 用的是 jne 指令,而 likely() 用的是 je 指令。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中,UNLIKELY是一个宏定义,用于提示编译器某个条件的发生概率较低。它一般用于if语句中,让编译器优化代码以提高性能。UNLIKELY可以与条件表达式结合使用,以告诉编译器这个条件很少会满足,从而优化代码的执行路径。通常,UNLIKELY用于if语句中的条件表达式,使得编译器更倾向于执行if语句中的else分支,以提高代码的执行效率。!!运算符是C语言中处理逻辑表达式的一个技巧,用于将非零值转换为1。当变量x为非零值时,!!(x)返回1,当x为零时,!!(x)返回0。这个技巧常用于将条件表达式的结果映射为布尔值。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [C语言技巧:有if时使用likelyunlikely让代码运行更快](https://blog.csdn.net/freestep96/article/details/128771498)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [C语言进阶——likelyunlikely](https://blog.csdn.net/weixin_44873133/article/details/107302688)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值