Liuw's Thinkpad

想要赢就先学会输,想要成功就先学会失败

Archive for the ‘optimization’ tag

The Story of “likely()” and “unlikely()”

without comments

“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.

Written by liuw

December 14th, 2009 at 11:07 am