Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hint for branch prediction in assertions

I have a custom ASSERT(...) macro which I use in a C++ application.

#include <stdlib.h>
#include <iostream>

/// ASSERT(expr) checks if expr is true.  If not, error details are logged
/// and the process is exited with a non-zero code.
#ifdef INCLUDE_ASSERTIONS
#define ASSERT(expr)                                                      \
    if (!(expr)) {                                                        \
        char buf[4096];                                                   \
        snprintf (buf, 4096, "Assertion failed in \"%s\", line %d\n%s\n", \
                 __FILE__, __LINE__, #expr);                              \
        std::cerr << buf;                                                 \
        ::abort();                                                        \
    }                                                                     \
    else // This 'else' exists to catch the user's following semicolon
#else
#define ASSERT(expr)
#endif

Recently I was reading some Linux kernel module code and came across the existence of likely(...) and unlikely(...) macros. These provide a hint to the CPU that a given branch is more likely, and that the pipeline should optimise for that path.

Assertions are, by definition, expected to evaluate to true (i.e. likely).

Can I provide a similar hint in my ASSERT macro? What's the underlying mechanism here?

Obviously I will measure for any difference in performance, but in theory should it make any difference?

I only run my code on Linux, but would be interested to know if there's a cross platform way of doing this too. I'm also using gcc, but would like to support clang as well.

like image 891
Drew Noakes Avatar asked May 28 '14 11:05

Drew Noakes


People also ask

How can branch prediction be improved?

One thing you can do in a high-level language is to eliminate branches by expressing the problem in terms of lookups or arithmetic. This helps branch prediction work better on the remaining branches, because there's more "history" available.

What is __ Builtin_expect in C?

You can use the __builtin_expect built-in function to indicate that an expression is likely to evaluate to a specified value. The compiler can use this knowledge to direct optimizations. This built-in function is portable with the GNU C/C++ __builtin_expect function.

What is branch prediction C++?

The branch prediction is based on the previous iterations on the same instruction. If the branches follow a regular pattern, the prediction are successful. The best cases are those in which a branch instruction has always the same effect; in such cases, the prediction is almost always correct.


2 Answers

The performance gain is not likely to be significant, but this is how those linux kernel macros are defined:

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

So, you could modify your condition like this (assuming that expr is expected to be true and therefore !(expr) is expected to be false):

if (__builtin_expect(!(expr), 0)) {

Or you could define the same macros as the kernel and use them for better readability.

This is gcc builtin, so not portable of course.

This suggests that clang also supports the builtin. Othrwise, you can use the above macros and conditionally define them like #define likely(x) (x) on compilers that don't support the builtin.

In your case, the prediction is going to be good (either that or you're aborting), so there shouldn't be a risk of pessimisation, but if you do consider using the builtin more widely, here's a word of advice from gcc documentation:

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.

like image 89
eerorika Avatar answered Sep 17 '22 15:09

eerorika


For many CPUs, likely and unlikely (or anything else for that matter) don't provide a branch hint to the CPU (only to the compiler, which may use it to optimize differently, similar to profile guided optimization) for the simple reason that there is no way to do it.

For example, branch hints are defined for x86 since P4. Before that they had no effect, but it's even worse, they have no effect on anything except P4. So they're useless (but waste space and bandwidth), and as far as I know GCC does not emit them.

ARM doesn't (yet?) have branch hints either. PPC, IA64 and SPARC do have hinted branches, I don't know whether GCC uses likely and unlikely for them though, but at least it could.

like image 35
harold Avatar answered Sep 17 '22 15:09

harold