最近在看内核代码时,在条件判断中出现了likely和unlike,比如在seq_read中有如下代码片段:
1 if (err < 0) 2 break; 3 if (unlikely(err)) 4 m->count = 0; 5 if (unlikely(!m->count)) { 6 p = m->op->next(m, p, &pos); 7 m->index = pos; 8 continue; 9 }
那么其作用是什么?
1 在linux/compiler.h中找到了定义
1 /* 2 * Generic compiler-dependent macros required for kernel 3 * build go below this comment. Actual compiler/compiler version 4 * specific implementations come from the above header files 5 */ 6 通用的编译器宏指令, 注:__builtin_expect由compiler在编译阶段理解并优化成指令流水,该语句并不是包含在某一头文件中 7 #define likely(x) __builtin_expect(!!(x), 1) 8 #define unlikely(x) __builtin_expect(!!(x), 0)
这里输入的参数x必须为整数,一般为条件表达式,返回为0或者1两种结果,使用likely时表示后面的判断成功概率大,使用unlikely时,表示后面的判断成功概率小,gcc解释如下:
這是使用 GCC 內的特殊 Function, 可以查 GCC Document
– 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 passing in 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 asif (__builtin_expect (ptr != NULL, 1))
error ();when testing pointer or floating-point values.
2 测试
2.1 测试unlikely
[kedar@ashwamedha ~]$ cat abc.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;
}
[kedar@ashwamedha ~]$ gcc -O2 -c abc.c
[kedar@ashwamedha ~]$ objdump -d abc.o
abc.o: file format elf32-i386
Disassembly of section .text:
00000000 :
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 >
^^^ --- The compiler branches the "if" block and keeps "else" sequential
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 >
2.2 测试likey
[kedar@ashwamedha ~]$ cat abc.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;
}
[kedar@ashwamedha ~]$ gcc -O2 -c abc.c
[kedar@ashwamedha ~]$ objdump -d abc.o
abc.o: file format elf32-i386
Disassembly of section .text:
00000000 :
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 >
^^^ --- The compiler branches the "else" block and keeps "if" sequential
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 >
但是在本机测试时,代码流未发生改变