博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
__builtin_expect详解
阅读量:4153 次
发布时间:2019-05-25

本文共 4260 字,大约阅读时间需要 14 分钟。

转自:http://hi.baidu.com/lammy/blog/item/bc5e3d4e869073c3d1c86a89.html

在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 
:   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
//主要看这里 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 
: 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
//主要看这里 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内核中也经常用到,国外也有一篇相关的文章,大家不妨看看:

不知大家注意到没有,我在生产汇编时用的是gcc -fprofile-arcs -O2 -c test_builtin_expect.c,而不是gcc -O2 -c test_builtin_expect.c,具体可以参考。

转载地址:http://gbgti.baihongyu.com/

你可能感兴趣的文章
985硕士:非科班自学编程感觉还不如培训班出来的,硕士白读了?
查看>>
你准备写代码到多少岁?程序员们是这么回答的!
查看>>
码农:和产品对一天需求,产品经理的需求是对完了,可我代码呢?
查看>>
程序员过年回家该怎么给亲戚朋友解释自己的职业?
查看>>
技术架构师的日常工作是什么?网友:搭框架,写公共方法?
查看>>
第四章 微信飞机大战
查看>>
九度:题目1008:最短路径问题
查看>>
九度Online Judge
查看>>
九度:题目1027:欧拉回路
查看>>
九度:题目1012:畅通工程
查看>>
九度:题目1017:还是畅通工程
查看>>
九度:题目1034:寻找大富翁
查看>>
第六章 背包问题——01背包
查看>>
51nod 分类
查看>>
1136 . 欧拉函数
查看>>
面试题:强制类型转换
查看>>
Decorator模式
查看>>
Template模式
查看>>
Observer模式
查看>>
高性能服务器设计
查看>>