__builtin_expect详解
在GTK+2.0源码中有很多这样的宏:G_LIKELY和G_UNLIKELY。比如下面这段代码:
if (G_LIKELY (acat == 1)) /* allocate through magazine layer */ { ThreadMemory *tmem = thread_memory_from_self(); guint ix = SLAB_INDEX (allocator, chunk_size); if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix))) { thread_memory_swap_magazines (tmem, ix); if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix))) thread_memory_magazine1_reload (tmem, ix); } mem = thread_memory_magazine1_alloc (tmem, ix); }
在源码中,宏G_LIKELY和G_UNLIKELY 是这么定义的:
#define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1)) #define G_UNLIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 0))
宏_G_BOOLEAN_EXPR的作用是把expr转换为0和1,即真假两种。要理解宏G_LIKELY和G_UNLIKELY ,很明显必须理解__builtin_expect。__builtin_expect是GCC(version>=2.9)引进的宏,其作用就是帮助编译器判断条件跳转的预期值,避免跳转造成时间乱费。拿上面的代码来说:
if (G_LIKELY (acat == 1)) //表示大多数情况下if里面是真,程序大多数直接执行if里面的程序
而
if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix)))//表示大多数情况if里面为假,程序大多数直接执行else里面的程序
可能大家看到还是一头雾水,看下面一段就会明白其中的乐趣啦;
//test_builtin_expect.c #define LIKELY(x) __builtin_expect(!!(x), 1)#define UNLIKELY(x) __builtin_expect(!!(x), 0)
int test_likely(int x){ if(LIKELY(x)) { x = 5; } else { x = 6; } return x;}
int test_unlikely(int x){ if(UNLIKELY(x)) { x = 5; } else { x = 6; } return x;}
[lammy@localhost test_builtin_expect]$ gcc -fprofile-arcs -O2 -c test_builtin_expect.c [lammy@localhost test_builtin_expect]$ objdump -d test_builtin_expect.o
test_builtin_expect.o: file format elf32-i386
Disassembly of section .text:
00000000 <test_likely>: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 8b 45 08 mov 0x8(%ebp),%eax 6: 83 05 38 00 00 00 01 addl $0x1,0x38 d: 83 15 3c 00 00 00 00 adcl $0x0,0x3c 14: 85 c0 test %eax,%eax 16: 74 15 je 2d <test_likely+0x2d>//主要看这里 18: 83 05 40 00 00 00 01 addl $0x1,0x40 1f: b8 05 00 00 00 mov $0x5,%eax 24: 83 15 44 00 00 00 00 adcl $0x0,0x44 2b: 5d pop %ebp 2c: c3 ret 2d: 83 05 48 00 00 00 01 addl $0x1,0x48 34: b8 06 00 00 00 mov $0x6,%eax 39: 83 15 4c 00 00 00 00 adcl $0x0,0x4c 40: 5d pop %ebp 41: c3 ret 42: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi 49: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
00000050 <test_unlikely>: 50: 55 push %ebp 51: 89 e5 mov %esp,%ebp 53: 8b 55 08 mov 0x8(%ebp),%edx 56: 83 05 20 00 00 00 01 addl $0x1,0x20 5d: 83 15 24 00 00 00 00 adcl $0x0,0x24 64: 85 d2 test %edx,%edx 66: 75 15 jne 7d <test_unlikely+0x2d>//主要看这里 68: 83 05 30 00 00 00 01 addl $0x1,0x30 6f: b8 06 00 00 00 mov $0x6,%eax 74: 83 15 34 00 00 00 00 adcl $0x0,0x34 7b: 5d pop %ebp 7c: c3 ret 7d: 83 05 28 00 00 00 01 addl $0x1,0x28 84: b8 05 00 00 00 mov $0x5,%eax 89: 83 15 2c 00 00 00 00 adcl $0x0,0x2c 90: 5d pop %ebp 91: c3 ret 92: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi 99: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
000000a0 <_GLOBAL__I_65535_0_test_likely>: a0: 55 push %ebp a1: 89 e5 mov %esp,%ebp a3: 83 ec 08 sub $0x8,%esp a6: c7 04 24 00 00 00 00 movl $0x0,(%esp) ad: e8 fc ff ff ff call ae <_GLOBAL__I_65535_0_test_likely+0xe> b2: c9 leave b3: c3 ret [lammy@localhost test_builtin_expect]$
两个函数编译生成的汇编语句所使用到的跳转指令不一样,仔细分析下会发现__builtin_expect实际上是为了满足在大多数情况不执行跳转指令,所以__builtin_expect仅仅是告诉编译器优化,并没有改变其对真值的判断。
这种用法在linux内核中也经常用到,国外也有一篇相关的文章,大家不妨看看:http://kernelnewbies.org/FAQ/LikelyUnlikely
不知大家注意到没有,我在生产汇编时用的是gcc -fprofile-arcs -O2 -c test_builtin_expect.c,而不是gcc -O2 -c test_builtin_expect.c,具体可以参考http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html。
__builtin_expect详解相关推荐
- (渗透测试后期)Linux进程隐藏详解
文章目录 (渗透测试后期)Linux进程隐藏详解 前言 Linux进程基础 Linux进程侦查手段 Linux进程隐藏手段 一.基于用户态的进程隐藏 方法1:小隐隐于/proc/pid--劫持read ...
- iOS runtime 底层详解、内部原理、场景应用
前言学:位域和共用体 一:isa指针--runtime之前的学习 1.1:苹果应用的按位或.按位与 二:类对象信息 2.1:类对象信息:rw_t 2.2:类对象信息:方法缓存(很关键) 2.2:类对象 ...
- 从命令行到IDE,版本管理工具Git详解(远程仓库创建+命令行讲解+IDEA集成使用)
首先,Git已经并不只是GitHub,而是所有基于Git的平台,只要在你的电脑上面下载了Git,你就可以通过Git去管理"基于Git的平台"上的代码,常用的平台有GitHub.Gi ...
- JVM年轻代,老年代,永久代详解
秉承不重复造轮子的原则,查看印象笔记分享连接↓↓↓↓ 传送门:JVM年轻代,老年代,永久代详解 速读摘要 最近被问到了这个问题,解释的不是很清晰,有一些概念略微模糊,在此进行整理和记录,分享给大家.在 ...
- docker常用命令详解
docker常用命令详解 本文只记录docker命令在大部分情境下的使用,如果想了解每一个选项的细节,请参考官方文档,这里只作为自己以后的备忘记录下来. 根据自己的理解,总的来说分为以下几种: Doc ...
- 通俗易懂word2vec详解词嵌入-深度学习
https://blog.csdn.net/just_so_so_fnc/article/details/103304995 skip-gram 原理没看完 https://blog.csdn.net ...
- 深度学习优化函数详解(5)-- Nesterov accelerated gradient (NAG) 优化算法
深度学习优化函数详解系列目录 深度学习优化函数详解(0)– 线性回归问题 深度学习优化函数详解(1)– Gradient Descent 梯度下降法 深度学习优化函数详解(2)– SGD 随机梯度下降 ...
- CUDA之nvidia-smi命令详解---gpu
nvidia-smi是用来查看GPU使用情况的.我常用这个命令判断哪几块GPU空闲,但是最近的GPU使用状态让我很困惑,于是把nvidia-smi命令显示的GPU使用表中各个内容的具体含义解释一下. ...
- Bert代码详解(一)重点详细
这是bert的pytorch版本(与tensorflow一样的,这个更简单些,这个看懂了,tf也能看懂),地址:https://github.com/huggingface/pytorch-pretr ...
最新文章
- 第1关:学习-用循环和数组实现输入某年某月某日,判断这一天一年的第几天
- 《强化学习周刊》第8期:强化学习应用之自然语言处理
- 并发编程之Synchronized原理
- VS2019中配置opencv4.3.0(亲测有效)
- 理解OAuth 2.0--转
- android系统设置在哪里,android-如何在系统settings里添加设置选项
- oracle ora06576,创建oracle发邮件job导致的故障
- BZOJ1787 [Ahoi2008]Meet 紧急集合 LCA
- 动态规划——矩阵中的最短路径长度
- 哪个Linux发行版运行kvm,如何在Linux发行版上安装和配置KVM和Open vSwitch
- ORA-01552 :非系统表空间 'xxxx'不能使用系统回退段
- 白话编程辅助工具perl2exe(Reship)
- sqlite 无符号32_《符号与传媒》2020年总目录
- 【渝粤教育】国家开放大学2018年秋季 0556-22T广告摄影 参考试题
- Qt5.10编写FTP客户端
- ora01031权限不足linux,ORA-01031:权限不足
- 图论,回路,旅行商、邮递员问题。
- android 系统输入法显示与隐藏监听
- 使用webpack-cli或vue-cli 解决ie兼容性与报错问题
- int a是神么意思
热门文章
- TFS2010映射工作区问题 路径 XXX 已在工作区 XXX;XXX 中映射
- 第四章 虚拟机的安装和使用
- 服务器lunix系统开启多用户,Ubuntu 服务器设置软件多用户访问
- 应用软件使计算机的内存分配更合理,应用软件使计算机的内存分配更合理,运行更加稳定()...
- html下拉列表初始值不显示,javascript – 使用innerhtml显示下拉列表文本而不是值...
- mysql error 1201_ERROR 1201 (HY000): Could not initialize master info structure; .....
- 字段 新增hive_Hive分区表 | 每日五分钟学大数据
- 【OS学习笔记】三十七 保护模式十:中断和异常的处理与抢占式多任务对应的汇编代码----主引导扇区代码
- 【小虫虫】邮购笔记本的注意事项
- [bzoj3994] [SDOI2015]约数个数和