解析Linux中的 likely 和 unlikely
Posted smartvxworks
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解析Linux中的 likely 和 unlikely相关的知识,希望对你有一定的参考价值。
目录
Linux 中多处出现 likely 和 unlikely 的使用,它们的定义如下:
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
1.函数原型
__builtin_expect 是 GCC 提供的内置函数 (built-in functions),函数原型是
long __builtin_expect (long exp, long c)
函数的返回值是 exp,它告诉编译器, 代码期望的是 exp == c 。
注意:代码中!!,并不是特殊符号,只是两次取反,通过这种技巧,可以将任意量转换为0或1。0 为 0,非 0 值为1。
2.使用该函数的作用
现代处理器的工作远超前于当前指令,比如从内存读新指令,译码指令等。只要指令遵循的是简单的顺序,那么这种指令流水线化就能很好的工作。当遇到分支的时候,处理器必须猜测分支该往哪个方向走,如果猜测错误,就会损失处理器的性能,因此需要分支预测技术。
__builtin_expect 就是用来为处理器的分支预测提供信息,帮助处理器进行分支预测。
if (unlikely(x))
do_something();
return x;
编译器会让主分支是概率最大的分支,尽量减少程序跳转的情况。以上代码会被编译器调整为如下的汇编逻辑。
if(x)
goto L1;
return x;
L1:
do_something();
return x;
2.1 通过汇编代码查看编译器实际动作
汇编代码如下:
normal_fun:
pushq %rbx
movl %edi, %ebx
testl %edi, %edi
jne .L4 ;normal 版本采用默认的分支预测
.L2:
movl %ebx, %eax
popq %rbx
ret
.L4:
movl $0, %eax
call do_something
jmp .L2
unlikely_fun:
pushq %rbx
movl %edi, %ebx
testl %edi, %edi
jne .L8 ;使等于1的情况作为跳转分支。
.L6:
movl %ebx, %eax
popq %rbx
ret
.L8:
movl $0, %eax
call do_something
jmp .L6
likely_fun:
pushq %rbx
movl %edi, %ebx
testl %edi, %edi
je .L10 ;使等于1的情况作为主分支。
movl $0, %eax
call do_something
.L10:
movl %ebx, %eax
popq %rbx
ret
3.总结
linux内核里的likely和unlikely实际上功能和if是一样的的,likely和unlikely在编译阶段,编译器对其进行了优化,减少分支,使得CPU执行更高效!
4.参考
Other Built-in Functions Provided by GCC
How do the likely/unlikely macros in the Linux kernel work and what is their benefit?
GCC __builtin_expect 解析
以上是关于解析Linux中的 likely 和 unlikely的主要内容,如果未能解决你的问题,请参考以下文章
Linux内核中的c语言:likely()unlikely()
Linux内核中的c语言:likely()unlikely()
Linux 内核源码中likely()和unlikely()
Linux 内核源码中likely()和unlikely()