Linux Kernel中的LIKELY和UNLIKELY

摘自:http://www.crazyshell.org/blog/?p=511

Linux Kernel中的LIKELY和UNLIKELY

常看到内核中的代码如下:

01 /* Note: the chip doesn't have auto-pad! */
02         if (likely(len < TX_BUF_SIZE)) {
03                 if (len < ETH_ZLEN)
04                     memset(tp->tx_buf[entry], 0, ETH_ZLEN);
05                 skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
06                 dev_kfree_skb(skb);
07         } else {
08                 dev_kfree_skb(skb);
09                 dev->stats.tx_dropped++;
10                 return NETDEV_TX_OK;
11         }
12 /* We received data from the HW, so stop the watchdog */
13         if (unlikely
14             (len + IL39_RX_FRAME_SIZE >
15              PAGE_SIZE << il->hw_params.rx_page_order)) {
16                 D_DROP("Corruption detected!\n");
17                 return;
18         }

如果你眼睛够细会看到likely 和 unlikely 这样的词. 在内核中它应该不是函数, 要是函数也应该是inline, 不过我觉得它更应该是一个宏
通过SI读源码, 可以看到它们被定义如下:

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

__builtin_expect作用是gcc内建的一条指令的优化,在一个条件经常出现, 或者该条件很少出现的时候, 编译后可以根据这条指令对条件分支选择优化

__builtin_expect((x),1)的意思是

1 if (__builtin_expect(!!(x),1)) {
2  
3 } else {
4  
5 }

表示这个if里面为真, 程序大多数直接执行if里面的程序

__builtin_expect((x),0) 则和上面相反直接执行else里面的程序.

来看段程序:

01 #define LIKELY(x)    __builtin_expect(!!(x), 1)
02 #define UNLIKELY(x)  __builtin_expect(!!(x), 0)
03  
04 int likely(int x) {
05  
06         if (LIKELY(x)) {
07                 x = 1;
08         } else {
09                 x = 2;
10         }
11         return x;
12 }
13  
14 int unlikely(int x) {
15  
16         if (UNLIKELY(x)) {
17                 x = 1;
18         } else {
19                 x = 2;
20         }
21         return x;
22 }
23  
24 int main() {
25  
26         likely(1);
27         unlikely(2);
28 }

然后看它汇编代码, 使用gcc -O2 -fprofile-arcs 来进行编.

01 Disassembly of section .text:
02  
03 0000000000000000 :
04    0:   48 83 05 00 00 00 00    addq   $0x1,0x0(%rip)        # 8
05    7:   01
06    8:   85 ff                   test   %edi,%edi
07    a:   74 06                   je     12
08    c:   b8 01 00 00 00          mov    $0x1,%eax
09   11:   c3                      retq
10   12:   48 83 05 00 00 00 00    addq   $0x1,0x0(%rip)        # 1a
11   19:   01
12   1a:   b8 02 00 00 00          mov    $0x2,%eax
13   1f:   c3                      retq
14  
15 0000000000000020 :
16   20:   48 83 05 00 00 00 00    addq   $0x1,0x0(%rip)        # 28
17   27:   01
18   28:   85 ff                   test   %edi,%edi
19   2a:   75 0e                   jne    3a
20   2c:   48 83 05 00 00 00 00    addq   $0x1,0x0(%rip)        # 34
21   33:   01
22   34:   b8 02 00 00 00          mov    $0x2,%eax
23   39:   c3                      retq
24   3a:   b8 01 00 00 00          mov    $0x1,%eax
25   3f:   c3                      retq

可以看出相同的程序,不同的likely的情况下, 程序分别使用了je和jne进行了优化.
对于编译代码的时候使用-fprofile-arcs , 原因如下:

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 use actual profile feedback for this (-fprofile-arcs), as programmers are notoriously bad at predicting how their programs actually perform. However, there are applications in which this data is hard to collect.

The return value is the value of exp, which should be an integral expression. The semantics 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 we expect x to be zero. Since you are limited to integral expressions for exp, you should use constructions such as

if (__builtin_expect (ptr != NULL, 1))
foo (*ptr);

when testing pointer or floating-point values.

原创文章,转载请注明出处:  http://www.crazyshell.org/blog/?p=511

我猜您可能还会喜欢:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值