CRuby Code Reading (1): LIKELY / UNLIKELY

LIKELY / UNLIKELY

Dies ist ein Artikel, in dem ich die CRuby-Implementierung lesen werde. Das ist das erste Mal.

Wenn Sie einen kurzen Blick auf die Rubinquelle werfen, finden Sie häufig das folgende Makro mit dem Namen "LIKELY / UNLIKELY".

Zitieren Sie vm_exec_core aus 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;
    }
}

Schauen Sie sich Zeile 9 an. Das ist UN LIKELY. Was ist das genau? Anscheinend wird es oft mit if verwendet. Zum Beispiel wird es hier auch als "if (UNLIKELY (reg_cfp == 0))" verwendet.

Grep LIKELY

Als ich also "#define LIKELY" aus der Ruby-Quelle grepte, fand ich die Makrodefinition 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 */

Wenn es nicht "__GNUC __> = 3" ist, scheint es, dass der Ausdruck einfach übernommen wird, also scheint es ein Makro für die Verwendung der ursprünglichen Erweiterung von GCC zu sein. Was ist "__builtin_expect" ...?

__builtin_expect

Ich habe die GCC-Dokumentation durchsucht und einen Artikel mit dem Namen [Other-Builtins] gefunden (https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html). Eine Beschreibung von __builtin_expect finden Sie in der Mitte der Seite. Unten ist das Zitat.

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

Verzweigungsvorhersage, Verzweigungsvorhersage! Mit anderen Worten, "__builtin_expect" scheint eine in GCC integrierte Funktion zu sein, die den "gemeinsamen Wert" angibt, den die angegebene Exp tatsächlich für die Verzweigungsvorhersage verwendet. Durch die Anzeige gemeinsamer Werte in dieser integrierten GCC-Funktion kann GCC bei der Erstellung weiterer Verzweigungen geeigneten Code ausspucken.

Lesen Sie LIKELY, UN LIKELY noch einmal

Lesen Sie nur die GCC-Version von LIKELY, UNLIKELY.

#define LIKELY(x)   (__builtin_expect((x), 1))
#define UNLIKELY(x) (__builtin_expect((x), 0))

__builtin_expect war eine integrierte Funktion, die angibt, dass der Ausdruck im ersten Argument häufig den Wert des zweiten Arguments annimmt. LIKELY (x) gibt also an, dass der Ausdruck x häufig 1 wird (normalerweise ein Wert von TRUE), und UNLIKELY (x) gibt an, dass x häufig 0 wird (ein Wert von FALSE).

Immerhin scheint Cruby die Betriebsgeschwindigkeit zum Zeitpunkt des GCC-Builds zu verbessern, indem geeignete LIKELY (x) und UNLIKELY (x) eingefügt werden.

Das war's.

Zusammenfassung

--LIKELY, UNLIKELY ist ein Makro, das dem Compiler zusätzliche Informationen für die Verzweigungsvorhersage gibt.

Apropos.

Der Wert von LIKELY wird als 1 angegeben. Ist es jedoch in Ordnung, wenn das Ergebnis der Vergleichsformel nicht 0 ist? Ich denke, es ist in Ordnung, wenn es wie "! Flag" mit expliziter Ablehnung ist, aber wenn Sie mit "LIKELY (ptr)" eine NULL-Prüfung für "ptr" durchführen, sollte der Wert nicht 1 sein. Wird das ohne Probleme gelöst? Zum Zeitpunkt des Lesens weiß ich nicht, wie man eine Ruby-Leistungsmessung durchführt, daher habe ich eine Weile nicht experimentiert. Wird beispielsweise eine Implementierung wie "#define LIKELY (x) __builtin_expect (!! (x), 1)" bereits in der Vergangenheit versucht ...? (Nein, natürlich kann dies zum Zeitpunkt des Durchlaufens von "!!" schwer sein, es ist also nur ein Beispiel, und es scheint, dass das Ergebnis ein wenig unklar sein wird.)

Recommended Posts

CRuby Code Reading (1): LIKELY / UNLIKELY
CRuby Code Reading (2): rb_newobj_of
CRuby-Code lesen (3): Ausgabe der Ausführungszeile rb_bug
Beim Lesen des Quellcodes
Rails 5 Code Reading Teil 2 ~ Aktionsansicht ~
Java-Quellcode zum Lesen der Klasse java.lang.Math