Understanding Linux kernel likely and unlikely macros

Linux kernel defines likely and unlikely macros in kernel source code include/linux/compiler.h as

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

As per GCC documentation, __builtin_expect has been described as,

Built-in Function: long __builtin_expect (long exp, long c)
You may use __builtin_expect to provide the compiler with branch prediction information.
if (__builtin_expect (x, 0))
  foo ();

indicates 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))
  foo (*ptr);

when testing pointer or floating-point values.

likely macro is used something like below in Linux kernel,

/**
 * kpp_request_alloc() - allocates kpp request
 *
 * @tfm:        KPP tfm handle allocated with crypto_alloc_kpp()
 * @gfp:        allocation flags
 *
 * Return: allocated handle in case of success or NULL in case of an error.
 */
static inline struct kpp_request *kpp_request_alloc(struct crypto_kpp *tfm,
                                                    gfp_t gfp)
{
        struct kpp_request *req;

        req = kmalloc(sizeof(*req) + crypto_kpp_reqsize(tfm), gfp);
        if (likely(req))
                kpp_request_set_tfm(req, tfm);

        return req;
}

Whereas, unlikely macro is used as,

/**
 * xdr_stream_encode_u32 - Encode a 32-bit integer
 * @xdr: pointer to xdr_stream
 * @n: integer to encode
 *
 * Return values:
 *   On success, returns length in bytes of XDR buffer consumed
 *   %-EMSGSIZE on XDR buffer overflow
 */
static inline ssize_t
xdr_stream_encode_u32(struct xdr_stream *xdr, __u32 n)
{
        const size_t len = sizeof(n);
        __be32 *p = xdr_reserve_space(xdr, len);

        if (unlikely(!p))
                return -EMSGSIZE;
        *p = cpu_to_be32(n);
        return len;
}

When we tried to emulate same likely & unlikely in application to understand how it works, you can check below program with comments to understand macros meanings,

 $ vim understanding_likely_unlikely.c 
#include <stdio.h>

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

int main(int argc, char **argv) {
        int x = 1;

        if (__builtin_expect(x, 0)) {
                printf("Value of x was expected to be 0 but x is =%d\n", x); 
//this shouldn't get called if x is 0
        }

        if(unlikely(x)) {
                printf("Value of x was expected to be 0 but x is =%d\n", x); 
//this shouldn't get called if x is 0
        }

        if (__builtin_expect(x, 1)) {
                printf("Value of x is expected to be 1\n"); 
//this should get called if x is 1
        }

        if(likely(x)) {
                printf("Value of x is expected to be 1\n"); 
//this should get called if x is 1
        }
        return 0;
}
Follow Lynxbee

Leave a Reply / Ask Question