How Do the Likely/Unlikely Macros in the Linux Kernel Work and What Is Their Benefit

How do the likely/unlikely macros in the Linux kernel work and what is their benefit?

They are hint to the compiler to emit instructions that will cause branch prediction to favour the "likely" side of a jump instruction. This can be a big win, if the prediction is correct it means that the jump instruction is basically free and will take zero cycles. On the other hand if the prediction is wrong, then it means the processor pipeline needs to be flushed and it can cost several cycles. So long as the prediction is correct most of the time, this will tend to be good for performance.

Like all such performance optimisations you should only do it after extensive profiling to ensure the code really is in a bottleneck, and probably given the micro nature, that it is being run in a tight loop. Generally the Linux developers are pretty experienced so I would imagine they would have done that. They don't really care too much about portability as they only target gcc, and they have a very close idea of the assembly they want it to generate.

Can likely/unlikely macros be used in user-space code?

Yes they can. In the Linux kernel, they are defined as

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

The __builtin_expect macros are GCC specific macros that use the branch prediction; they tell the processor whether a condition is likely to be true, so that the processor can prefetch instructions on the correct "side" of the branch.

You should wrap the defines in an ifdef to ensure compilation on other compilers:

#ifdef __GNUC__
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif

It will definitely give you optimizations if you use it for correct branch predictions.

likely()/unlikely() macros in the Linux kernel with a segmentation fault

__builtin_expect (used in the definition of the likely/unlikely macros) doesn't generate actual code to evaluate either of its arguments. All it does is tell the compiler what result to expect if it were evaluated.

It might confuse the optimizer if you tell it that *(int*)NULL is usually 13, but (barring compiler bugs) it won't segfault the compiler, or produce code which segfaults at run-time.

Another answer on the old question has actual asm with/without the macro, showing that their effect is in how gcc lays out the code (e.g. putting the unlikely case off by itself, and the likely case in the fall-through not-taken side of a conditional branch where instruction-cache misses are less likely).


This isn't quite a duplicate of likely()/unlikely() macros in the Linux kernel - how do they work? What's their benefit?, but you will find much more info about how these macros work and what their effect is on that Q&A.

Using Likely() / Unlikely() Preprocessor Macros in if-else if chain

You shall make this explicit:

if (A)
return true;
else if (B)
return true;
...
else if (Y)
return true;
else {
if (likely(Z))
return true;

raiseError();
return false;
}

Now compiler clearly understands your intention and will not reassign other branch probabilities. Also readability of code increased.

P.S. I suggest you to rewrite also likely and unlikely in the way Linux kernel do to protect from silent integral casts:

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

Why doesn't likely and unlikely macros have any effect on ARM assembly code?

As @rici said, your code is simple enough that it can be realized by conditional instructions. You can see a difference, e.g., if you call functions which are implemented in a different compilation unit:

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

// only forward declarations:
void foo();
void bar();

int main(char *argv[], int argc)
{
if (likely (argc == 2))
foo();
else
bar();
}

Changing likely to unlikely switches the order of the if and else branch, for ARM and x86: https://godbolt.org/z/UDzvf0. If this really makes a difference likely depends on the hardware you are running on, whether you call the function the first time (otherwise, the CPU-internal branch prediction likely has a higher influence than the order of the instructions), and probably many other things.

Using a likely/unlikely as argument of return in linux kernel

Just guessing here, but imagine the function is inlined by the compiler, and you have this in the calling code:

if (functionUsingUnlikelyForReturn()) {
// Do something
} else {
// Do something different
}

then it's entirely reasonable for the branch prediction to take note of the hint.

How do you include debug info for assembly files in the Linux kernel?

if building with llvm clang, remove ifndef CONFIG_AS_IS_LLVM and endif from around the KBUILD_AFLAGS

diff --git a/scripts/Makefile.debug b/scripts/Makefile.debug
index 9f39b0130551f..1a26df0538b5b 100644
--- a/scripts/Makefile.debug
+++ b/scripts/Makefile.debug
@@ -6,9 +6,7 @@ else
DEBUG_CFLAGS += -g
endif

-ifndef CONFIG_AS_IS_LLVM
KBUILD_AFLAGS += -Wa,-gdwarf-2
-endif

ifndef CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT
dwarf-version-$(CONFIG_DEBUG_INFO_DWARF4) := 4


Related Topics



Leave a reply



Submit