Built-in Macros in the Linux Kernel
The Linux kernel uses several built-in macros to optimize performance. Two commonly used macros are defined in include/linux/compiler.h:
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
These macros internally use the built-in function __builtin_expect(). While __builtin_expect() has a name that directly suggests its function, likely and unlikely provide a more readable and intuitive way to use it in the kernel code.
Understanding __builtin_expect()
long __builtin_expect (long exp, long c);
This is a GCC built-in function that provides branch prediction hints to the compiler. It helps optimize performance by positioning rarely used code paths at the end of a function, improving cache efficiency and reducing branch mispredictions.
Debugging and Branch Profiling
When debugging or profiling branch execution, the kernel uses an extended version of these macros:
include/linux/compiler.h
#if defined(CONFIG_TRACE_BRANCH_PROFILING) \
&& !defined(DISABLE_BRANCH_PROFILING) && !defined(__CHECKER__)
void ftrace_likely_update(struct ftrace_likely_data *f, int val,
int expect, int is_constant);
#define likely_notrace(x) __builtin_expect(!!(x), 1)
#define unlikely_notrace(x) __builtin_expect(!!(x), 0)
#define __branch_check__(x, expect, is_constant) ({ \
long ______r; \
static struct ftrace_likely_data \
__aligned(4) \
__section("_ftrace_annotated_branch") \
______f = { \
.data.func = __func__, \
.data.file = __FILE__, \
.data.line = __LINE__, \
}; \
______r = __builtin_expect(!!(x), expect); \
ftrace_likely_update(&______f, ______r, \
expect, is_constant); \
______r; \
})
/*
* Using __builtin_constant_p(x) to ignore cases where the return
* value is always the same. This idea is taken from a similar patch
* written by Daniel Walker.
*/
# ifndef likely
# define likely(x) (__branch_check__(x, 1, __builtin_constant_p(x)))
# endif
# ifndef unlikely
# define unlikely(x) (__branch_check__(x, 0, __builtin_constant_p(x)))
# endif
These macros help track branch execution statistics when debugging is enabled.
Recommended by LinkedIn
__builtin_constant_p()
int __builtin_constant_p(x);
Using likely() and unlikely() in Linux System Programs
Since likely() and unlikely() are kernel-defined macros, using them in user-space programs will result in compilation errors. However, you can use __builtin_expect() directly in general C applications.
If a condition in a branch statement is highly predictable, using __builtin_expect() can improve performance. However, if branch predictability is uncertain, it's best to let the compiler handle optimization.
Example Program
Below is a simple test program to demonstrate __builtin_expect() in action:
#include <stdio.h>
int test_func(int input)
{
if (__builtin_expect(input > 0, 1))
{
input += 8;
input *= 4;
}
else
{
input -= 8;
input /= 4;
}
return input;
}
int main()
{
printf("Output: %d\n", test_func(3));
return 0;
}
In this example:
Using branch prediction optimizations like likely(), unlikely(), and __builtin_expect() can significantly improve performance in large-scale applications, particularly in performance-critical areas such as data processing and system-level programming.
Senior Emulation Engineer at Renesas | Ex-NXP | Ex- ST | PEC Chandigarh
2moYes very helpful but needs little attention during wrong prediction as pipeline needs to be flushed.
Staff Software Engineer, DataCore | Ex-Veritas | Ex-RedHat | Ex-HP | Ex-Cisco
3moDo you think we should be using __builtin_expect() directly?
Embedded software engineer
3moYes likely and unlikely is used alot in kernel code, and the purpose for same as you said above is branch prediction which inturn effect pipeline at processor level to improve efficiency.
Technologist & Believer in Systems for People and People for Systems
3moVery informative and services to the same for the good 😊