Chinaunix首页 | 论坛 | 博客
  • 博客访问: 115934
  • 博文数量: 11
  • 博客积分: 565
  • 博客等级: 中士
  • 技术积分: 267
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-02 17:17
文章分类
文章存档

2014年(1)

2012年(2)

2011年(4)

2010年(4)

我的朋友

分类: LINUX

2010-08-05 21:18:15


大多数时候,linux内核会把一个变量与一个外部值比较来看某一条件是否已满足,这种比较的结果很大程度上是可以预测的。这样的例子很常见,例如,检查合法性的代码。内核使用likelyunlikely两个宏分别表示返回的结果是true(1)false(0)。这两个宏使用gcc可根据它的返回值来优化编译结果的特性来提升代码的性能。

这里有个例子,我们假设调用do_something()函数,在出错的情况下,我们调用handle_error来处理错误:

err = do_something(x, y, z);
if(err)
    handle_error(err);


如果do_something很少出错,我们可以将代码重写为:


err = do_something(x, y, z);
if(unlikely(err))
    handle_error(err);


下面具体分析likelyunlikely

首先要明确:

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 后面的语句的机会更大。

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

第一个例子: 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 来观察汇编指令,结果如下:

# 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, "else" block is more probable */
                x = 5;
                x = x * x;
        } else {
                x = 6;
        }
        return x;
}


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

编译以后,通过 objdump 来观察汇编指令,结果如下:


# 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


阅读(2252) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~