转载自:http://velep.com/archives/795.html
本文讲的likely()和unlikely()两个宏,在linux内核代码和一些应用中可常见到它们的身影。实质上,这两个宏是关于GCC编译器内置宏__builtin_expect的使用。
顾名思义,likely()指“很有可能”之意,而unlikely()指“不太可能”之意。那么,在实际应用中,它们代表什么?又是怎么使用的呢?下面是一篇外文翻译(加上了本人的一些理解),给出了详细答案。likely()和unlikely()对于linux内核代码,在条件判断语句中经常看到likely()和unlikely()的调用,如下代码所示:bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx);if (unlikely(!bvl)) { mempool_free(bio, bio_pool); bio = NULL; goto out;}
#define likely(x) __builtin_expect(!!(x), 1)#define unlikely(x) __builtin_expect(!!(x), 0)
-- 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 value of C must be a compile-time constant. 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)) error (); when testing pointer or floating-point values.
#define likely(x) __builtin_expect(!!(x), 1)#define unlikely(x) __builtin_expect(!!(x), 0) int main(char *argv[], int argc){ int a; /* 获取输入参数值(编译器不能进行优化) */ a = atoi (argv[1]); if (unlikely (a == 2)) a++; else a--; printf ("%d\n", a); return 0;}
80483b0:// 开头80483b0: 55 push %ebp80483b1: 89 e5 mov %esp,%ebp80483b3: 50 push %eax80483b4: 50 push %eax80483b5: 83 e4 f0 and $0xfffffff0,%esp// 调用atoi()80483b8: 8b 45 08 mov 0x8(%ebp),%eax80483bb: 83 ec 1c sub $0x1c,%esp80483be: 8b 48 04 mov 0x4(%eax),%ecx80483c1: 51 push %ecx80483c2: e8 1d ff ff ff call 80482e4 80483c7: 83 c4 10 add $0x10,%esp// 把输入值与2进行比较,即执行:“a == 2”80483ca: 83 f8 02 cmp $0x2,%eax// --------------------------------------------------------// 如果'a' 等于 2 (程序里面认为不太可能), 则跳转,// 否则继续执行, 从而不破坏CPU的指令执行顺序.// --------------------------------------------------------80483cd: 74 12 je 80483e1 80483cf: 48 dec %eax// 调用printf80483d0: 52 push %edx80483d1: 52 push %edx80483d2: 50 push %eax80483d3: 68 c8 84 04 08 push $0x80484c880483d8: e8 f7 fe ff ff call 80482d4 // 返回0并退出.80483dd: 31 c0 xor %eax,%eax80483df: c9 leave80483e0: c3 ret
80483b0:// 开头80483b0: 55 push %ebp80483b1: 89 e5 mov %esp,%ebp80483b3: 50 push %eax80483b4: 50 push %eax80483b5: 83 e4 f0 and $0xfffffff0,%esp// 调用atoi()80483b8: 8b 45 08 mov 0x8(%ebp),%eax80483bb: 83 ec 1c sub $0x1c,%esp80483be: 8b 48 04 mov 0x4(%eax),%ecx80483c1: 51 push %ecx80483c2: e8 1d ff ff ff call 80482e4 80483c7: 83 c4 10 add $0x10,%esp// --------------------------------------------------// 如果'a' 等于 2 (程序认为很有可能), 则不跳转,继续执行,// 这样就不破坏CPU的指令执行顺序.// 只有当 a != 2 时才会发生跳转, 而这种情况,程序认为是不太可能的.// ---------------------------------------------------80483ca: 83 f8 02 cmp $0x2,%eax80483cd: 75 13 jne 80483e2 // a++ 指令的优化80483cf: b0 03 mov $0x3,%al// 调用printf()80483d1: 52 push %edx80483d2: 52 push %edx80483d3: 50 push %eax80483d4: 68 c8 84 04 08 push $0x80484c880483d9: e8 f6 fe ff ff call 80482d4 // 返回0并退出.80483de: 31 c0 xor %eax,%eax80483e0: c9 leave80483e1: c3 ret