CRuby code reading (1): LIKELY / UNLIKELY

LIKELY / UNLIKELY

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))`.

Grep LIKELY

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 LIKELY, UN LIKELY again

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.

Summary

--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.

by the way.

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.)

Recommended Posts

CRuby code reading (1): LIKELY / UNLIKELY
CRuby code reading (2): rb_newobj_of
CRuby code reading (3): rb_bug execution line output
When reading the source code
Rails 5 Code Reading Part 2 ~ Action View ~
Java source code reading java.lang.Math class