Archive for the ‘unlikely’ tag
The Story of “likely()” and “unlikely()”
“likely()” and “unlikely()” are macros defined in Linux kernel. But the true story is about optimization.
#define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0)
These macros can be used in user space, though. Because they are in fact some built-in features of gcc(1). gcc(1) should optimize assembly generation according to program’s need.
Try this simple sample.
int main()
{
int a;
if (likely(a == 100))
printf("Branch 1\n");
else
printf("Branch 2\n");
return 0;
}
I use an uninitialized variable, that’s a bug, but this does not affect my demostration. Feel free to ignore that uninitialized “a”, we just need something to compare to a constant, don’t we? If I use two constants for comparison, gcc(1) will optimize in compile time and we can not see the outcoming of “likely()” and “unlikely()”.
Use gcc(1) to generate assembly.
$ gcc -S -O2 likely.c
Here is what we get. Ignore less important part, focus on most valuable snippet.
cmpl $100, %eax
jne .L2
movl $.LC0, (%esp)
call puts
.L4:
addl $4, %esp
xorl %eax, %eax
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.L2:
movl $LC1, (%esp)
call puts
jmp .L4
Pay attention to that “jne” directive. We compare variable (which stores in eax) with 100 to see if they are equal. The outcoming result is “likely” to be true, so that “jne” is not executed, the code just falls through. The benifit we get is that no jumping means no pipe line flush, we can make full use of directive cache.
If I change “likely” to “unlikely” in my C code, assembly code generation will be different. However, it should follow the same rule as above – make full use of pipe line.