免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2381 | 回复: 0
打印 上一主题 下一主题

内核中 likely(x) 和 unlikely(x) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-10-19 21:42 |只看该作者 |倒序浏览
本帖最后由 tbag-tang 于 2010-10-23 21:09 编辑

在内核源码中经常出现以下两个宏:likely(x) 和 unlikely(x)
其定义如下:

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

我先解释下这里的gcc内建函数 __builtin_expect
在/usr/include/gmp-i386.h中有如下说明.
/* __builtin_expect is in gcc 3.0, and not in 2.95. */

__builtin_expect(!!(x), 1)
        这里表示条件为真的可能性比较大
__builtin_expect(!!(x), 0)
        这里表示条件为假的可能性比较大
注:如果x为0,则!!(x)还是0; 如果x不为0,则!!(x)为1.

真的是这样吗? 带着这个疑问接着往下看。

测试程序如下:
1) __builtin_expect(!!(x), 0)

// test.c
#include <stdio.h>

void ketty(int va)
{
        if (__builtin_expect(!!(va), 0)) {
                va = va + 8;
        }
        else {
                va = va + 98;
        }

        printf("%d\n", va);
}

int main(void)
{
        ketty(1);

        return 0;
}

编译及反汇编过程如下:
tbag@:~/test$ gcc -O2 test.c -o unlikely
tbag@:~/test$ objdump -D unlikely > unlike
tbag@:~/test$        vi unlike

08048410 <ketty>:
8048410:        55                           push   %ebp
8048411:        89 e5                        mov    %esp,%ebp
8048413:        83 ec 18                     sub    $0x18,%esp
8048416:        8b 45 08                     mov    0x8(%ebp),%eax
------------------------------------------------------------
8048419:        85 c0                        test   %eax,%eax
804841b:        75 1c                        jne    8048439 <ketty+0x29>
804841d:        b0 62                        mov    $0x62,%al

------------------------------------------------------------
804841f:        89 44 24 08                  mov    %eax,0x8(%esp)
8048423:        c7 44 24 04 20 85 04         movl   $0x8048520,0x4(%esp)
804842a:        08
804842b:        c7 04 24 01 00 00 00         movl   $0x1,(%esp)
8048432:        e8 f5 fe ff ff               call   804832c <__printf_chk@plt>
8048437:        c9                           leave  
8048438:        c3                           ret   
------------------------------------------------------------
8048439:        83 c0 08                     add    $0x8,%eax
------------------------------------------------------------
804843c:        eb e1                        jmp    804841f <ketty+0xf>
804843e:        66 90                        xchg   %ax,%ax

TEST   指令对两个操作数作按位与运算,将影响的标记记在标志位中,  
       供查询使用,而源目操作数均不改变。
note: 这里使用的是jne(知道这点很重要),紧跟其后的是else语句块里的代码


2) __builtin_expect(!!(x), 1)

#include <stdio.h>

void ketty(int va)
{
        if (__builtin_expect(!!(va), 1)) {
                va = va + 8;
        }
        else {
                va = va + 98;
        }

        printf("%d\n", va);
}

int main(void)
{
        ketty(1);

        return 0;
}

编译及反汇编过程如下:
tbag@:~/test$ gcc -O2 test.c -o likely
tbag@:~/test$ objdump -D likely > like
tbag@:~/test$        vi like

08048410 <ketty>:
8048410:        55                           push   %ebp
8048411:        89 e5                        mov    %esp,%ebp
8048413:        83 ec 18                     sub    $0x18,%esp
8048416:        8b 45 08                     mov    0x8(%ebp),%eax
------------------------------------------------------------
8048419:        85 c0                        test   %eax,%eax
804841b:        74 1d                        je     804843a <ketty+0x2a>
804841d:        83 c0 08                     add    $0x8,%eax

------------------------------------------------------------
8048420:        89 44 24 08                  mov    %eax,0x8(%esp)
8048424:        c7 44 24 04 20 85 04         movl   $0x8048520,0x4(%esp)
804842b:        08
804842c:        c7 04 24 01 00 00 00         movl   $0x1,(%esp)
8048433:        e8 f4 fe ff ff               call   804832c <__printf_chk@plt>
8048438:        c9                           leave  
8048439:        c3                           ret   
------------------------------------------------------------
804843a:        b0 62                        mov    $0x62,%al
------------------------------------------------------------
804843c:        eb e2                        jmp    8048420 <ketty+0x10>
804843e:        66 90                        xchg   %ax,%ax

note: 这里使用的是je,紧跟其后的是if语句块里的代码。

分析:
1.__builtin_expect(!!(x), 0)
        a) 使用的是jne跳转指令。
        b) 通过反汇编可以看出, 编译器将if语句块里面的代码放在else语句块之后。
也就是说,编译器将“预期"的小概率事件放在代码段的后面。

2.__builtin_expect(!!(x), 1)
        .) 跟__builtin_expect(!!(x), 0) 刚好相反。

这样做有什么优化吗?
我来说下我的个人观点:
.Cache
        根据局部性原理,CPU总是将最近访问主存的数据存储到cache中. 这样的话,大概率事件放在代码前面,命中
的机率就越大,也就是说将小概率事件放在代码段后面,就越能提高Cache的使用效率。
        以下是摘自ARM System Developer's Guide: Designing and System Software的一段对Cache的描述。

        cache is a small, fast array of memory placed between the processor and main memory. It
is a holding buffer that stores portions of recently referenced system memory. The processor
uses cache memory in preference to system memory whenever possible to increase average
system performance.

以上是我的一些认识。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP