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.
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With