likely(x)与unlikely(x)函数,即__builtin_expect的使用

转载自:http://velep.com/archives/795.html

 

本文讲的likely()和unlikely()两个宏,在linux内核代码和一些应用中可常见到它们的身影。实质上,这两个宏是关于GCC编译器内置宏__builtin_expect的使用。

顾名思义,likely()指“很有可能”之意,而unlikely()指“不太可能”之意。那么,在实际应用中,它们代表什么?又是怎么使用的呢?下面是一篇外文翻译(加上了本人的一些理解),给出了详细答案。

likely()和unlikely()

对于linux内核代码,在条件判断语句中经常看到likely()和unlikely()的调用,如下代码所示:

bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx);
if (unlikely(!bvl)) {mempool_free(bio, bio_pool);bio = NULL;goto out;
}


在这里,调用likely()或unlikely()告诉编译器这个条件很有可能或者不太有可能发生,好让编译器对这个条件判断进行正确地优化。这两个宏在include/linux/compiler.h文件中可以找到:

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


在GCC文档中可找到上述代码中__builtin_expect的说明,摘录如下:

    -- 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 useactual profile feedback for this (`-fprofile-arcs'), as
        programmers are notoriously bad at predicting how their programsactually perform.  However, there are applications in which thisdata is hard to collect.The return value is the value of EXP, which should be an integralexpression.  The value of C must be a compile-time constant.  Thesemantics 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 weexpect `x' to be zero.  Since you are limited to integralexpressions for EXP, you should use constructions such asif (__builtin_expect (ptr != NULL, 1))error ();when testing pointer or floating-point values.


__builtin_expect说明中给出了两示例:

if (__builtin_expect (x, 0)) foo (); 表示期望x == 0,也就是不期望不执行foo()函数;同理,if (__builtin_expect (ptr != NULL, 1)) error (); 表示期望指针prt非空,也就是不期望看到error()函数的执行。

编译器做的优化工作

从GCC的说明中可知,__builtin_expect的主要作用就是:帮助编译器判断条件跳转的预期值,避免因执行jmp跳转指令造成时间浪费。那么它是怎么帮助编译器进行优化的呢?

编译器优化时,根据条件跳转的预期值,按正确地顺序生成汇编代码,把“很有可能发生”的条件分支放在顺序执行指令段,而不是jmp指令段(jmp指令会打乱CPU的指令执行顺序,大大影响CPU指令执行效率)。

下面举例说明。下面这个简单的C程序使用gcc -O2进行编译。

#define likely(x)    __builtin_expect(!!(x), 1)
#define unlikely(x)  __builtin_expect(!!(x), 0)int main(char *argv[], int argc)
{int a;/* 获取输入参数值(编译器不能进行优化) */a = atoi (argv[1]);if (unlikely (a == 2))a++;elsea--;printf ("%d\n", a);return 0;
}


使用objdump -S反汇编,查看它的汇编代码。

80483b0 <main>:
//             开头
80483b0:       55                      push   %ebp
80483b1:       89 e5                   mov    %esp,%ebp
80483b3:       50                      push   %eax
80483b4:       50                      push   %eax
80483b5:       83 e4 f0                and    $0xfffffff0,%esp
//             调用atoi()
80483b8:       8b 45 08                mov    0x8(%ebp),%eax
80483bb:       83 ec 1c                sub    $0x1c,%esp
80483be:       8b 48 04                mov    0x4(%eax),%ecx
80483c1:       51                      push   %ecx
80483c2:       e8 1d ff ff ff          call   80482e4 <atoi@plt>
80483c7:       83 c4 10                add    $0x10,%esp
//             把输入值与2进行比较,即执行:“a == 2”
80483ca:       83 f8 02                cmp    $0x2,%eax
//             --------------------------------------------------------
//             如果'a' 等于 2 (程序里面认为不太可能), 则跳转,
//             否则继续执行, 从而不破坏CPU的指令执行顺序.
//             --------------------------------------------------------
80483cd:       74 12                   je     80483e1 <main+0x31>
80483cf:       48                      dec    %eax
//             调用printf
80483d0:       52                      push   %edx
80483d1:       52                      push   %edx
80483d2:       50                      push   %eax
80483d3:       68 c8 84 04 08          push   $0x80484c8
80483d8:       e8 f7 fe ff ff          call   80482d4 <printf@plt>
//             返回0并退出.
80483dd:       31 c0                   xor    %eax,%eax
80483df:       c9                      leave
80483e0:       c3                      ret


在上面程序中,用likely()代替其中的unlikely(),重新编译,再来看它的汇编代码:

80483b0 <main>:
//             开头
80483b0:       55                      push   %ebp
80483b1:       89 e5                   mov    %esp,%ebp
80483b3:       50                      push   %eax
80483b4:       50                      push   %eax
80483b5:       83 e4 f0                and    $0xfffffff0,%esp
//             调用atoi()
80483b8:       8b 45 08                mov    0x8(%ebp),%eax
80483bb:       83 ec 1c                sub    $0x1c,%esp
80483be:       8b 48 04                mov    0x4(%eax),%ecx
80483c1:       51                      push   %ecx
80483c2:       e8 1d ff ff ff          call   80482e4 <atoi@plt>
80483c7:       83 c4 10                add    $0x10,%esp
//             --------------------------------------------------
//             如果'a' 等于 2 (程序认为很有可能), 则不跳转,继续执行,
//             这样就不破坏CPU的指令执行顺序.
//             只有当 a != 2 时才会发生跳转, 而这种情况,程序认为是不太可能的.
//             ---------------------------------------------------
80483ca:       83 f8 02                cmp    $0x2,%eax
80483cd:       75 13                   jne    80483e2 <main+0x32>
//             a++ 指令的优化
80483cf:       b0 03                   mov    $0x3,%al
//             调用printf()
80483d1:       52                      push   %edx
80483d2:       52                      push   %edx
80483d3:       50                      push   %eax
80483d4:       68 c8 84 04 08          push   $0x80484c8
80483d9:       e8 f6 fe ff ff          call   80482d4 <printf@plt>
//             返回0并退出.
80483de:       31 c0                   xor    %eax,%eax
80483e0:       c9                      leave
80483e1:       c3                      ret


如何使用?

在一个条件判断语句中,当这个条件被认为是非常非常有可能满足时,则使用likely()宏,否则,条件非常非常不可能或很难满足时,则使用unlikely()宏。

参考资料

本文英文原文:http://kernelnewbies.org/FAQ/LikelyUnlikely

更多GCC内置宏或函数,详见:http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html

转载于:https://www.cnblogs.com/pengdonglin137/articles/3808631.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/260312.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java mvc引擎_SpringMvc+JavaConfig+Idea 搭建项目

1.介绍之前搭建SpringMvc项目要配置一系列的配置文件&#xff0c;比如web.xml,applicationContext.xml,dispatcher.xml。Spring 3.X之后推出了基于JavaConfig方式以及注解的形式的配置。在一定程度上简化了Spring项目的配置。近几年特别火的SpringBoot&#xff0c;大大的简化了…

window.parent和window.opener区别

下面一段代码是关于window.parent和window.opener区别 来讲的&#xff0c;我们如果要用到iframe的值传到另一框架就要用到window.opener.document.getElementById(name).value uvalue;这种形式哦。 window.parent能获取一个框架的父窗口或父框架。顶层窗口的parent引用的是它本…

极域电子书包课堂管理系统_【君莲微讯】君莲学校(小学部)开展电子书包第13共同体数学研讨活动...

借 助 媒 体 技 术丰 富 图 形 认 识君莲学校(小学部)开展电子书包共同体 数学研讨活动 2020年12月2日下午&#xff0c;君莲学校(小学部)开展了以“借助媒体技术 丰富图形认识”为主题的闵行区电子书包第13共同体的数学研讨活动。共同体学校教师代表、学校电子书包项目组主管朱…

python批量改动指定文件夹文件名称

这小样例仅仅要是说明用python怎么批量改动指定文件夹的文件名称&#xff1a; 记得要把脚本跟改动的文件放在同一个文件夹下 #encoding:utf-8 import os import sys files os.listdir(D:\\1) #路径能够自己for name in files:a os.path.splitext(name)if a[1] .txt: #txt能够…

Linux vmstat命令实战详解

vmstat命令是最常见的Linux/Unix监控工具&#xff0c;可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率&#xff0c;内存使用&#xff0c;虚拟内存交换情况,IO读写情况。这个命令是我查看Linux/Unix最喜爱的命令&#xff0c;一个是Linux/Unix都支持&#xff0c;二是…

python的基础网络编程是下列_Python入门基础之网络编程、socket编程、TCP、UDP编程...

忙了两天&#xff0c;继续更文&#xff01;希望多多支持。套接字套接字是一种具有之前所说的"通讯端点"概念的计算机网络数据结构。网络化的应用程序在开始任何通讯之前都必需要创建套接字。套接字有三种&#xff1a;1、 AF_UNIX(在 POSIX1.g 标准中也叫 AF_LOCAL)&a…

java 入门 博客园_javaweb入门

复习&#xff1a;css的常用样式&#xff1a;borderbackgroundpaddingmarginfloatposition 定位top left确定div在页面中的位置&#xff0c;这两个值可以为负数。cssdiv 布局方式cssdivtable 先由div划分大块儿&#xff0c;再由table进行整齐布局。下拉列表&#xff1a;层叠的布…

以ThreadStart方式实现多线程

3.1 使用ThreadStart委托 这里先以一个例子体现一下多线程带来的好处&#xff0c;首先在Message类中建立一个方法ShowMessage()&#xff0c;里面显示了当前运行线程的Id&#xff0c;并使用Thread.Sleep&#xff08;int ) 方法模拟部分工作。在main()中通过ThreadStart委托绑定M…

管理思考

管理基础 分活 分钱 分责任 分权 安人(安排 配置) 流程 标准 考核 治人(协调 指挥 控制) 社会越来越复杂 分工越来越复杂 合作越来越重要 目标一定要一致共同的意愿共识 需要大家参与管理 业务划分 责任划分 流程梳理 如何合作做好安全工作 安全服务因为不承担责任 责任主体是管…

我的atom插件

atom插件实在是太多了&#xff0c;下面就说说我的插件 1.minimap 右边的小地图&#xff0c;和sublime里面的差不多&#xff1b; 2.open-in-browser 右击默认浏览器打开&#xff1b; 3.emmet 这个不用多说吧&#xff0c;html快速编译 4.git-plus 直接在atom提交代码&#xff0…

python统计英文句子每个单词字数_Python小书3-文本英文单词统计

之前写Python Web小书第三小节本来用的垃圾邮件的案例三郎&#xff1a;Python贝叶斯推理垃圾邮件分类​zhuanlan.zhihu.com后来发现里面的东西&#xff0c;涉及到概率&#xff0c;程序太复杂了。。。哈哈哈所以就想着&#xff0c;哪天重写一下&#xff0c;选来选去&#xff0c;…

java9特性_96.java基础10(java9/10/11新特性)

126.java 9 新特性1(模块化功能):1.java模块化2.java 交互式环境jshell3.泛型package com.atguigu.java;import org.junit.Test;import java.io.IOException;import java.io.InputStreamReader;import java.net.MalformedURLException;import java.net.URL;import java.util.Ar…

MonoRail - 简介 [基础知识篇]

MonoRail - 简介 起源 MonoRail是一个.NET的MVC web开发框架, 原名Castle On Rails, 是CastleProject的一个子项目. 作者hammett在使用过Ruby On Rails后, 觉得非常棒, 他希望在享受ror的开发模式的同时能使用大量现有的资源, 于是就用.NET写出了一个Castle On Rails. 后来ror那…

结对编程(黄金点游戏)

我扮演的角色是驾驶员 一、结对伙伴 领航员&#xff1a;赵峻 作业地址见我的博客。 二、代码地址 https://coding.net/u/k2048/p/huangjindian/git/blob/master/main.c 三、总结 1、个人总结 本次作业我扮演驾驶员&#xff0c;赵峻扮演领航员&#xff0c;我负责算法实现以及代码…

qtgl 鼠标平移 c++_罗技真爱粉的MX Master 3无线鼠标体验

​这是一篇关于罗技MX Master3的晒单&#xff0c;顺带也翻出我的库存清洁整理一下吧。在决定购买一款新鼠标的时候&#xff0c;我的第一目标其实是MX Vertical垂直鼠标&#xff0c;不过MX Vertical目前优势只在外形上&#xff0c;在MX系列中明显属于低配&#xff0c;自由滚轮、…

java实验指导书(实验四)答案_java程序设计实验指导书答案

? 狗生活在陆地上(是一种陆生动物)&#xff0c;既是哺乳类的也是肉食性的。狗通常的时候和人打招呼会通过“摇摇尾巴”&#xff0c;在被抚摸感到舒服的时候&#xff0c;会“旺旺叫”&#xff0c;而在受到惊吓情绪烦躁时&#xff0c;会发出“呜呜”声&#xff1b;? 猫也生活在…

php代码规范说明文档

命名规则&#xff1a;采用驼峰标识&#xff0c;尽量做到见名知义 PHP编码规范与原则&#xff1a; //命名&#xff1a;类&#xff0c;方法&#xff0c;函数&#xff0c;变量&#xff0c; 注释&#xff1a;开发中难免留下一些临时代码和调试代码&#xff0c;此类代码必须添加注释…

下载网页中的图片到本地

简单的一个下载如下 &#xff1a; string url "http://avatar.csdn.net/A/2/6/2_yefengzhixia.jpg";string filepath "D:\\pic.jpg";WebClient mywebclient new WebClient();mywebclient.DownloadFile(url, filepath);MessageBox.Show("OK");…

nacos linux启动_微服务系列之Nacos配置中心之一:Nacos介绍与安装

一、Nacos 介绍Nacos 是 Alibaba 公司推出的开源工具&#xff0c;用于实现分布式系统的服务发现与配置管理。英文全称 Dynamic Naming and Configuration Service&#xff0c;Na 为 Naming/NameServer 即注册中心&#xff0c;co 为 Configuration 即配置中心&#xff0c;Servic…

演练:在组件设计器中创建 Windows 服务应用程序

http://msdn.microsoft.com/zh-cn/library/zt39148a(vvs.80).aspx 演练&#xff1a;在组件设计器中创建 Windows 服务应用程序 .NET Framework 2.0其他版本5&#xff08;共 5&#xff09;对本文的评价是有帮助 - 评价此主题注意 Visual Studio 标准版中不提供“Windows 服务”模…