« 什么是asmlinkage | Main | DoWhile(0) »
likely() and unlikely() (转)
By lerosua | 09月 25, 2008
(前言:之前我译过这版likelyUnlikely,但由于旧的博客坏了,再也找不回那篇文章了。但发现另有网友翻译了,由此转自http://blog.chinaunix.net/u/27708/showart_680626.html)
内核FAQ之LikelyUnlikely
作者: Haitao
likely() and unlikely()
它们是指什么?
在linux内核代码中,经常看到likely()和unlikely()会在条件语句中调用到,如:
事实上,根据这两个函数可以得知条件语句中最可能发生的情形,从而告知编译器以允许它正确地优化条件分支。
在include/linux/complier.h头文件中可以找到它们的宏定义:
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
在gcc文档中是这样来解释__builtin_expect()的作用:
-- Built-in Function: long __builtin_expect (long EXP, long C)
The return value is the value of EXP, which should be an integral if (__builtin_expect (x, 0)) would indicate that we do not expect to call `foo’, since we if (__builtin_expect (ptr != NULL, 1)) when testing pointer or floating-point values. |
如何来优化的?
通过合理地安排生成的汇编代码来加以 优化,进而充分地发挥处理器的pipeline流水线性能。这样,可以安排最可能发生的条件分支代码并不执行任何的jmp指令(jmp指令的使用会导致刷 新处理器流水线的负效应)。为说明上述优化过程,我们以gcc -O2 优化编译选项来编译接下来的C用户空间程序:
#define likely(x) __builtin_expect(!!(x), 1)
int main(int argc, /* Get the value from somewhere GCC can’t optimize */ if (unlikely (a == 2)) printf (”%d\n”, a); return 0; |
由gcc -O2 -o test test.c编译产生最终的可执行二进制文件,并利用objdump -S对产生的二进制文件进行反汇编,以得到优化之后的汇编代码,如下(其中加入了注释):
080483b0 <main>:
// 如果’a'等于2(这种情形最不可能发生),就jump跳转执行;否则继续顺序往下 // 执行,不存在jump跳转,这样就不会刷新流水线pipeline。 // ——————————————————– 80483cd: 74 12 je 80483e1 <main+0x31>
// 此处,eax直接进行自减,即a--
80483cf: 48 dec %eax
// Call printf
80483d0: 52 push %edx
80483d1: 52 push %edx
80483d2: 50 push %eax
80483d3: 68 c8 84 04 08 push $0x80484c8
80483d8: e8 f7 fe ff ff call 80482d4 <printf@plt>
// Return 0 and go out.
80483dd: 31 c0 xor %eax,%eax
80483df: c9 leave
80483e0: c3 ret
|
同样,我们修改前面的程序,用likely()代替unlikely(),重新编译和反汇编,如下(其中已经添加了注释):
080483b0 <main>: |
什么时候应该使用likely()和unlikely()?
当存在最最可能发生的分支情形时,使用likely();而当存在最最不可能发生的分支情形时,使用unlikely()。
原文地址 http://kernelnewbies.org/FAQ/LikelyUnlikely
Topics: kernelnewbies | 2 Comments »