内核中的 likely() 与 unlikely()

Linux 内核源码中likely()和unlikely() ikely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢?首先明确:if (likely(value))等价于if (value)if (likely(a>b)) {fun1();if (unlikely(value))等价于if (value)也就是说likely()和unlikely()从阅读和理解的角度是一样的。这两个宏在内核中定义如下:#defi 阅读详情

原文: http://blog.youkuaiyun.com/rstevens/article/details/1798561


内核中的 likely() 与 unlikely()


在 2.6 内核中,随处可以见到 likely() 和 unlikely() 的身影,那么为什么要用它们?它们之间有什么区别?

首先要明确:

            if(likely(value)) 等价于 if(value)

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

也就是说 likely() 和 unlikely() 从阅读和理解代码的角度来看,是一样的!!!


这两个宏在内核中定义如下:

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


__builtin_expect() 是 GCC (version >= 2.96)提供给程序员使用的,目的是将“分支转移”的信息提供给编译器,这样编译器可以对代码进行优化, 以减少指令跳转带来的性能下降。

__builtin_expect((x),1) 表示 x 的值为真的可能性更大;
__builtin_expect((x),0) 表示 x 的值为假的可能性更大。

也就是说,使用 likely() ,执行 if 后面的语句 的机会更大,使用unlikely(),执行else 后面的语句的机会更大。
例如下面这段代码,作者就认为 prev 不等于 next 的可能性更大,

if  (likely(prev  !=  next)) {
       next
-> timestamp  =  now;
        ...
} 
else  {
        ...;
 }

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


下面以两个例子来加深这种理解:

第一个例子: example1.c

int  testfun( int  x)
{
        
if (__builtin_expect(x,  0 )) {
                              
^^^---  We instruct the compiler,  " else "  block  is  more probable
                x 
=   5 ;
                x 
=  x  *  x;
        } 
else  {
                x 
=   6 ;
        }
        
return  x;
}

在这个例子中,我们认为 x 为0的可能性更大

编译以后,通过 objdump 来观察汇编指令,在我的 2.4 内核机器上,结果如下:

# gcc -O2 -c  example1.c
# objdump -d  example1.o

Disassembly of section .text:

00000000   < testfun > :
   
0 :    55                       push    % ebp
   
1 :    89  e5                   mov     % esp, % ebp
   
3 :   8b  45   08                 mov     0x8 ( % ebp), % eax
   
6 :    85  c0                   test    % eax, % eax
   
8 :    75   07                    jne     11   < testfun + 0x11 >
   a:   b8 
06   00   00   00           mov    $ 0x6 , % eax
   f:   c9                      leave
  
10 :   c3                      ret
  
11 :   b8  19   00   00   00           mov    $ 0x19 , % eax
  
16 :   eb f7                   jmp    f  < testfun + 0xf >


可以看到,编译器使用的是 jne (不相等跳转)指令,并且 else block 中的代码紧跟在后面。

  8 :    75   07                    jne     11   < testfun + 0x11 >
 a:   b8 
06   00   00   00           mov    $ 0x6 , % eax


第二个例子: example2.c


int  testfun( int  x)
{
        
if (__builtin_expect(x,  1 )) {
                              
^^^   ---  We instruct the compiler,  " if "  block  is  more probable
                x 
=   5 ;
                x 
=  x  *  x;
        } 
else  {
                x 
=   6 ;
        }
        
return  x;
}

在这个例子中,我们认为 x 不为 0 的可能性更大

编译以后,通过 objdump 来观察汇编指令,在我的 2.4 内核机器上,结果如下:

# gcc -O2 -c  example2.c
# objdump -d  example2.o


Disassembly of section .text:

00000000   < testfun > :
   
0 :    55                       push    % ebp
   
1 :    89  e5                   mov     % esp, % ebp
   
3 :   8b  45   08                 mov     0x8 ( % ebp), % eax
   
6 :    85  c0                   test    % eax, % eax
   
8 :    74   07                    je      11   < testfun + 0x11 >
   a:   b8 
19   00   00   00           mov    $ 0x19 , % eax
   f:   c9                      leave
  
10 :   c3                      ret
  
11 :   b8  06   00   00   00           mov    $ 0x6 , % eax
  
16 :   eb f7                   jmp    f  < testfun + 0xf >


这次编译器使用的是 je (相等跳转)指令,并且 if block 中的代码紧跟在后面。

   8 :    74   07                    je      11   < testfun + 0x11 >
   a:   b8 
19   00   00   00           mov    $ 0x19 , % eax


=========================必不可少的实验========================

根据上面的代码,我在自己的机器上试了试,照着做结果不一样。
如果你和我一样,可以再读读这篇文章:http://blog.youkuaiyun.com/huntinux/article/details/11369851
查看gcc man文档也可以:

GCC will use heuristics to guess branch probabilities
           if they are not provided by profiling feedback
           (-fprofile-arcs).  These heuristics are based on the
           control flow graph.  If some branch probabilities are
           specified by __builtin_expect, then the heuristics
           will be used to guess branch probabilities for the
           rest of the control flow graph, taking the
           __builtin_expect info into account.  The interactions
           between the heuristics and __builtin_expect can be
           complex, and in some cases, it may be useful to
           disable the heuristics so that the effects of
           __builtin_expect are easier to understand.

编译命令改为:
$ gcc -fprofile-arcs -O2 -c e1.c


KT148A语音芯片SOP外挂功放芯片8002D的说明_V1 KT148A语音芯片内置8欧姆0.5W的功放,所以一般的应用场景,播放一些提示音音量是足够的。但是有的需求还需要驱动更大的扬声器,实现更大的播放音量,这里我们给出解决方案。KT148A+HAA8002D的组合 阅读详情

相关推荐

Vue+ECharts-GL 3D地图实战:5层叠加打造炫酷中国地图(附完整代码)

本文详细介绍了如何利用Vue和ECharts-GL构建具有强烈立体感的3D中国地图。通过5层图层的巧妙叠加与样式调校,实现了从背景阴影到交互高光的完整视觉层次,并整合了动态飞线与散点标记。文章提供了完整的代码实现、核心配置解析以及性能优化与视觉调优的实战技巧,帮助开发者快速打造专业级的交互式地图可视化应用。

d6e7f8g9h的博客 649

内核的likely和unlikely

1. 概念 指令周期是指执行一条指令所需要的时间,一般由若干个机器周期组成,是从取指令、分析指令到指令执行完所需的全部。 预取指令具体方法就是在不命中时,当数据从主存储器中取出送往CPU的同时,把主存储器相邻几个单元中的数据(称为一个数据块)都取出来送入Cache中。预取指令可以更好的利用 cpu资源。简单说就是从内存取指令很慢, cpu要等待这个过程。如果能提前预测可能执行的指令,就提前从内...

To_run_away的博客 1677

用野火FPGA开发板(EP4CE10)手把手教你实现一个高精度频率计(附完整Verilog代码)

本文详细介绍了基于野火FPGA开发板(EP4CE10)实现高精度频率计的全过程,涵盖等精度测量法的核心原理、Verilog代码实现及优化技巧。通过实际案例演示,帮助开发者掌握1Hz-50MHz范围、精度达0.1%的频率计设计方法,并提供完整的工程代码和实测数据。

weixin_29261711的博客 439

深入了解glibc的互斥锁的加锁过程

深入了解glibc的互斥锁

小x的博客 1644

Unity序列帧动画输出全攻略:Recorder+Timeline实战与透明通道处理

序列帧动画是游戏开发、影视动画和UI动效中的基础技术,指将连续动作分解为一系列静态图像并按序播放,形成动态视觉效果。其原理是通过时间轴精确控制每一帧的内容与时机,实现动画的逐帧呈现。在实时渲染领域,序列帧输出技术价值显著,它能够将动态内容高质量地转换为静态图像序列,便于跨平台复用、后期合成与资源分发。应用场景广泛,包括角色动画导出、技能特效制作、宣传片素材生成等。本文聚焦Unity引擎,深入解析如何利用Recorder与Timeline工具链,高效输出带Alpha透明通道的PNG序列帧,并重点攻克透明通道处

weixin_31556767的博客 327

别再到处找资源了!WinCC 7.5 SP2官方下载与Windows 10保姆级安装避坑指南

本文提供了WinCC 7.5 SP2在Windows 10上的官方下载与安装全流程指南,重点解决了资源获取难、系统兼容性问题及分卷压缩处理等常见痛点。通过详细的步骤和实用技巧,帮助用户顺利完成安装并优化配置,适用于工控领域的学习者和从业者。

weixin_32924297的博客 475

__glibc_unlikely and __glibc_likely

【代码】__glibc_unlikely and __glibc_likely。

qq_38963393的博客 349

足式机器人全身 MPPI: 利用 MPPI 对足式机器人进行实时全身控制

本研究首次在真实四足机器人上成功部署了基于全身采样的模型预测控制(MPC)系统。采用模型预测路径积分(MPPI)算法,通过并行采样和评估控制轨迹实现实时运动规划。该系统能处理复杂接触场景,完成推箱子、爬越障碍及崎岖地形行走等任务。实验使用Unitree Go1机器人,结合MuJoCo仿真器快速生成运动策略,仅需简单控制策略即可实现稳健操作。硬件验证表明,该方法能有效完成目标导向的箱子推动任务。该成果标志着采样MPC在足式机器人实际应用中的重要突破。

2506_90492529的博客 999

Linux线程的创建

创建进程的话,调用的系统调用是fork,在copy_process函数里面,会将五大结构 files_struct、fs_struct、sighand_struct、signal_struct、mm_struct都复制一遍,从此父进程 和子进程各用各的数据结构。而创建线程的话,调用的是系统调用clone,在copy_process函数 里面, 五大结构仅仅是引用计数加一,也即线程共享进程的数据结构。

PnJgHT的博客 2015

边缘计算与产业生态系统

目录 文章目录目录边缘计算产业参与者边缘计算产业生态系统 边缘计算产业参与者 边缘计算领域参与者众多,主流公司以打造生态优势为目标,基于自身服务层级向产业链上下两端进行拓展,目前市场主要参与者有: 系统集成商:在产业头部,具有广泛的能力,可以集成不同生态系统公司的产品,具有一定的全球性属性,在边缘计算领域大多由云服务商、电信运营商担任。 云服务商:具有领先的云技术优势与应用生态体系,同时拥有全球性资源布局与市场资源生态,并渴望成为边缘计算主导者。 电信运营商:具有边缘基础设施优势,以及不可替代的

烟云的计算 2100

手把手教你ensp仿真搭建校园网(含防火墙及无线网络)系列(一)校园网核心交换机配置

本系列博客将带你从零开始,使用 华为 eNSP(Enterprise Network Simulation Platform) 仿真搭建一个完整的校园网络,涵盖 核心层、汇聚层、接入层、防火墙安全策略、无线AC+AP组网 等实战场景。无论你是网络初学者还是希望深化实战经验的工程师,都能通过本教程掌握企业级网络的规划、配置与排错技巧。

echo的博客 3795

__builtin_expect提高运行效率

这个指令是gcc引入的,作用是"允许程序员将最有可能执行的分支告诉编译器"。这个指令的写法为:__builtin_expect(EXP, N)。意思是:EXP==N的概率很大。 给出glibc-2.28中 cdefs.h    misc\sys    18008    2018/8/1     #if __GNUC__ &gt;= 3 # define __glibc_unlikely(c...

RToax 1260

手把手教你搭建工业级C#上位机:完整架构+通信+配置+日志,新手也能落地(附全套源码)

模型层是“数据容器”,统一数据格式,避免参数传递混乱。本文搭建的C#上位机,采用“分层+模块化”架构,解耦了UI、通信、配置、日志四大核心功能,不仅满足工业场景的基础需求,还为后续扩展打下基础。新手跟着步骤走,既能掌握上位机的核心开发技能,又能理解工业级项目的架构设计思路。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1154

linux内核中的likely()和unlikely()宏的作用

在看linux内核代码的时候,经常会看到likely(x)和unlikely(x)宏的使用。那这两个宏有什么作用呢? 这两个宏在内核中的定义如下: # define likely(x) __builtin_expect(!!(x), 1) # define unlikely(x) __builtin_expect(!!(x), 0) 可见这里使用了gcc的内建函数__builtin_exp

落尘纷扰的专栏 2万+

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Linux内核中的c语言:likely()、unlikely()

在Linux内核中,会发现很多likely()和unlikely()的使用。

rayylee 915

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Linux内核中的likely()和unlikely()宏

在Linux内核代码中经常看到likely()和unlikely()这两个宏,它们都是对bool变量进行判定,其定义如下: # define likely(x)__builtin_expect(!!(x), 1) # define unlikely(x)__builtin_expect(!!(x), 0) 其中__builtin_expect()函数是gcc提供的用于对分支语句进行优化,其原型如下: long __builtin_expect (long exp, long c) 当exp ==..

jinking01的专栏 906
上一篇: Slope One算法
下一篇: __builtin_expect详解
春泥面包
博客等级 码龄18年 109粉丝 195原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值