This is an article that I will read about the CRuby implementation. This is the first time.
If you take a quick look at the ruby source, you will often find the following macro called "LIKELY / UNLIKELY".
Quote vm_exec_core from vm_exec.c in CRuby
static VALUE
vm_exec_core(rb_thread_t *th, VALUE initial)
{
register rb_control_frame_t *reg_cfp = th->cfp;
while (1) {
reg_cfp = ((rb_insn_func_t) (*GET_PC()))(th, reg_cfp);
if (UNLIKELY(reg_cfp == 0)) {
break;
}
}
if (th->retval != Qundef) {
VALUE ret = th->retval;
th->retval = Qundef;
return ret;
}
else {
VALUE err = th->errinfo;
th->errinfo = Qnil;
return err;
}
}
Look at line 9. This is UN LIKELY. What exactly is this? Apparently it is often used with if. For example, it is also used here as ʻif (UNLIKELY (reg_cfp == 0))`.
So when I grep #define LIKELY
from the ruby source, I found the macro definition in internal.h.
/* likely */
#if __GNUC__ >= 3
#define LIKELY(x) (__builtin_expect((x), 1))
#define UNLIKELY(x) (__builtin_expect((x), 0))
#else /* __GNUC__ >= 3 */
#define LIKELY(x) (x)
#define UNLIKELY(x) (x)
#endif /* __GNUC__ >= 3 */
Unless __GNUC__> = 3
, it seems that the expression is simply adopted, so it seems to be a macro for using GCC's original extension.
What is __builtin_expect
...?
__builtin_expect
I searched the GCC documentation and found an article called Other-Builtins.
You can find a description of __builtin_expect
in the middle of the page. Below is the quote.
— Built-in Function: long __builtin_expect (long exp, long c) You may use __builtin_expect to provide the compiler with branch prediction information. 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. However, there are applications in which this data is hard to collect.
The return value is the value of exp, which should be an integral expression. The semantics of the built-in are that it is expected that exp == c. For example:
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.
branch prediction, branch prediction!
In other words, __builtin_expect
seems to be a GCC built-in function to indicate the" common value "that the specified exp actually takes for branch prediction.
By showing common values in this GCC built-in function, GCC will be able to spit out the appropriate code when doing that branch.
Read only the GCC version of LIKELY, UNLIKELY.
#define LIKELY(x) (__builtin_expect((x), 1))
#define UNLIKELY(x) (__builtin_expect((x), 0))
__builtin_expect
was a built-in function that indicates that the expression in the first argument often takes the value of the second argument.
So LIKELY (x) indicates that the expression x often goes to 1 (often the value of TRUE), and UNLIKELY (x) shows that x often goes to 0 (the value of FALSE).
After all, by inserting appropriate LIKELY (x) and UNLIKELY (x), cruby seems to improve the operation speed at the time of GCC build.
I see.
--LIKELY and UNLIKELY are macros for giving auxiliary information for branch prediction to the compiler. --LIKELY usually uses expressions that are TRUE --UNLIKELY usually uses formulas that become FALSE --CRuby makes fine adjustments to branch prediction, including its own extension.
The value of LIKELY is specified as 1, but is it okay if the result of the comparison formula is other than 0?
Maybe it's okay if it's like ! Flag
with explicit negation, but if you do a NULL check on ptr
with LIKELY (ptr)
, the value shouldn't be 1. Will that be solved without any problems?
At the time of reading, I don't know how to perform ruby performance measurement, so I haven't experimented for a while.
For example, is an implementation like #define LIKELY (x) __builtin_expect (!! (x), 1)
already tried in the past ...?
(No, of course, this may be heavy at the time of passing through !!
, so it is just an example, and it seems that the result will be a little unclear.)