首页 > 其他分享 >内核中的 likely() 与 unlikely()

内核中的 likely() 与 unlikely()

时间:2022-10-11 13:04:20浏览次数:35  
标签:__ 00 mov expect eax likely unlikely 内核

在 2.6 内核中,随处可以见到 likely() 和 unlikely() 的身影,那么为什么要用它们?它们之间有什么区别? 
首先要明确: 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 后面的语句的机会更大。
例如下面这段代码,作者就认为 prev 不等于 next 的可能性更大,if (likely(prev != next)) {
next->timestamp = now;
...
} 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 来观察汇编指令,在我的 2.4 内核机器上,结果如下:
# gcc -O2 -c example1.c
# objdump -d example1.oDisassembly 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, "if" block is more probable
x = 5;
x = x * x;
} else {
x = 6;
}
return x;
}
在这个例子中,我们认为 x 不为 0 的可能性更大编译以后,通过 objdump 来观察汇编指令,在我的 2.4 内核机器上,结果如下:
# 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

标签:__,00,mov,expect,eax,likely,unlikely,内核
From: https://blog.51cto.com/u_14934686/5746147

相关文章

  • ubuntu 20.04升级软件包和内核
    一、升级所有软件包命令企业中经常会遇到linux被检测出漏洞,对于核心业务,需要有针对性的升级,但是对于某些业务,漏洞特别多,而且容易恢复的,可以考虑使用简单的命令升级sudoap......
  • 驱动开发:内核R3与R0内存映射拷贝
    在上一篇博文《驱动开发:内核通过PEB得到进程参数》中我们通过使用KeStackAttachProcess附加进程的方式得到了该进程的PEB结构信息,本篇文章同样需要使用进程附加功能,但这次我......
  • 驱动开发:内核R3与R0内存映射拷贝
    在上一篇博文《驱动开发:内核通过PEB得到进程参数》中我们通过使用KeStackAttachProcess附加进程的方式得到了该进程的PEB结构信息,本篇文章同样需要使用进程附加功能,但这次......
  • 驱动开发:内核通过PEB得到进程参数
    PEB结构(ProcessEnvirormentBlockStructure)其中文名是进程环境块信息,进程环境块内部包含了进程运行的详细参数信息,每一个进程在运行后都会存在一个特有的PEB结构,通过附......
  • 驱动开发:内核通过PEB得到进程参数
    PEB结构(ProcessEnvirormentBlockStructure)其中文名是进程环境块信息,进程环境块内部包含了进程运行的详细参数信息,每一个进程在运行后都会存在一个特有的PEB结构,通过附......
  • centos7.x内核升级到5.19.12
    [root@docker~]#uname-r#查看内核版本,centos7.x默认是3.10.0Linuxdocker3.10.0-1160.el7.x86_64#1SMPMonOct1916:18:59UTC2020x86_64x86_64x86_......
  • 内核查看previousmode
    进入内核NtCreateFile中,如果需要查看是由用户态进入的还是从内核态进入的,可以使用如下命令.thread查看当前线程kd>.threadImplicitthreadisnow87272880dt_KTHREA......
  • aardio 利用chrome内核开发
    importwin.ui;importchrome.app/*DSG{{*/varwinForm=win.form(text="helloworld";right=800;bottom=500)/*}}*/varapp=chrome.app(winForm)//varurl="http://lo......
  • 报错:禁用了全局ipv6转发,但当前在内核中未禁用
    报错ERROR:[/etc/sysconfig/network-scripts/ifup-ipv6]GlobalIPv6forwardingisdisabledinconfiguration,butnotcurrentlydisabledinkernelERROR......
  • 驱动开发:内核取ntoskrnl模块基地址
    模块是程序加载时被动态装载的,模块在装载后其存在于内存中同样存在一个内存基址,当我们需要操作这个模块时,通常第一步就是要得到该模块的内存基址,模块分为用户模块和内核模块......