Ever wondered what the likely and unlikely macros in the linux kernel are ?
The macros are defined as :
#define likely(x) __builtin_expect((x),1) #define unlikely(x) __builtin_expect((x),0)
The __builtin_expect is a method that gcc (versions >= 2.96) offer for programmers to indicate branch prediction information to the compiler. The return value of __builtin_expect is the first argument (which could only be an integer) passed to it.
To check it out how it could be beneficial, an excerpt from "info gcc" :
if (__builtin_expect (x, 0))
foo ();
[This] would indicate that we do not expect to call `foo', since we
expect `x' to be zero.
Based on this information the compiler generates intelligent code, such that the most expected result is favored.
[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 >
And let us see what happens if we make the "if" block more likely.
[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 >
thanks!
Thanks for the info! The same problem was troubling me for some time. I couldnt figure out why there were 2 different functions with different parameters, yet returned the same value.
Thanks for the info!
Nice! I was wonder what the heck unlikely() was for when reading through some code. Now it makes a lot of sense.
Very helpful
Very well explained ! That helped a lot man !
I’ve still two doubts
I’ve still two doubts (sorry but I’m not so familiar with compilers):
1) In the example above we have "if {...}else{...};" I wonder which optimizations does gcc adds if the "else" statement has been omitted? In this case can we have a real improvement using likely/unlikely macros?
2) Supposing we have the following condition checks:
if (errtest1){
...
if (errtest2){
...
}
if (errtest3){
...
}
...
}
and most of time these returns false; so I want to add the unlikely macro.
Is it necessary to put the unlikely macro in each conditions or I only need to add it in the first line?
I think all the compiler
I think all the compiler cares about is what is the next instruction that is to be executed if the "if" condition is unlikely. That next instruction could be part of the "else", or another "if", or another may be something else. Although, the space allocation of code is much more easier in case of the if/else than the others.
You could write similar problems and find out what it actually does.
unlikely is a hint about a boolean expression
In order:
As an example, the following code can compile to two different forms:
/* before if */
if(error)
{
/* log error */
}
/* after if */
Either the compiler decides to branch if error is true, resulting in code like:
/* before if */
MOVS R0, error
BNE ifBlock
afterIf:
/* after if */
...
ifBlock:
/* log error */
B afterIf
Alternatively, it can decide to branch if error is false, resulting in code like
/* before if */
MOVS R0, error
BEQ afterIf
/* log error */
/* after if */
Taking a branch tends to be costly, so you want to avoid taking branches whenever you can. By using likely() and unlikely(), you can persuade the compiler to generate code that doesn't normally take the branch, which runs faster. In this example, putting unlikely() around error would make the compiler more likely to generate the first block of code (faster whenever error is false), whereas putting likely() around error would make the compiler more likely to generate the second block of code (faster whenever error is true).
Even if you have an else block, likely() and unlikely() can help; most CPUs have some form of static branch prediction, and likely() and unlikely() can be used by the compiler to help it generate code where the CPU's static branch predictor gets it right more often than not.
How this works on different architectures?
How this works on different architectures at runtime branch prediction?
there is no connection
there is no connection between these two. this is compiler optimization, simply, don't jump for more likely branches.