likely() and unlikely()

In Linux kernel code, we often find some calls to likely() and unlikely , in branch. For example:

static inline int rt_policy(int policy)
{
    if (unlikely(policy == SCHED_FIFO || policy == SCHED_RR))
        return 1;
    return 0;
}

It's not vital for us to figure out what it is and the tricks behind it.

What is it ?

In fact, these functions are hints for the compiler that allows it to correctly optimize the branch, by knowing which is the likeliest one. The definitions of these macros, found in include/linux/compiler.h are the following :

#define likely(x)       __builtin_expect(!!(x), 1)
#define unlikely(x)     __builtin_expect(!!(x), 0)

The GCC documentation explains the __builtin_expect() :

-- 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 return 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 as

          if (__builtin_expect (ptr != NULL, 1))
            error ();

     when testing pointer or floating-point values.

In short:**__builtin_expect ** receive two params. EXP, which means expression, must be a integer value, 0 or 1. The value of C is expected to equal to EXP. The return value is the function is EXP. For example

  if (__builtin_expect (ptr != NULL, 1))
            error ();

The code means that if we expect the expression of ptr!=NULL is true(1 in code). The error function will execute if the ptr!=NULL, so we expect the error() should be executed.

How does it optimize things ?

It optimizes things by ordering the generated assembly code correctly, to optimize the usage of the processor pipeline. Specially, they arrange the code so that the likeliest branch is executed without performing any jmp instruction (which has the bad effect of flushing the processor pipeline). For example, we have the C code below:

 if (unlikely (a == 2))
      a++;
   else
      a--;

The assmebly code of that is

 80483ca:       83 f8 02                cmp    $0x2,%eax
 80483cd:       74 12                   je     80483e1 
 //             --------------------------------------------------------
 //             If 'a' equal to 2 (which is unlikely), then jump,
 //             otherwise continue directly, without jump, so that it
 //             doesn't flush the pipeline.
 //             --------------------------------------------------------

If we change the unlikely() to likely(), the assmebly code shows as below:

80483ca:       83 f8 02                cmp    $0x2,%eax
 80483cd:       75 13                   jne    80483e2 
//             --------------------------------------------------
 //             If 'a' equal 2 (which is likely), we will continue
 //             without branching, so without flusing the pipeline. The
 //             jump only occurs when a != 2, which is unlikely.
 //             ---------------------------------------------------

你可能感兴趣的:(likely() and unlikely())