C'est un article que je vais lire l'implémentation de CRuby. C'est la première fois.
Si vous jetez un coup d'œil rapide à la source de ruby, vous trouverez souvent la macro suivante "PROBABLE / UNLIKELY".
Citer vm_exec_core de vm_exec.c dans 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;
}
}
Regardez la ligne 9. C'est UN PROBABLEMENT. Qu'est-ce que c'est exactement? Apparemment, il est souvent utilisé avec if. Par exemple, il est également utilisé ici comme ʻif (UNLIKELY (reg_cfp == 0)) `.
Donc, quand je grep #define LIKELY
à partir de la source ruby, j'ai trouvé la définition de la macro dans 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 */
À moins que «__GNUC __> = 3», il semble que l'expression soit simplement adoptée, donc cela semble être une macro pour utiliser l'extension originale de GCC. Qu'est-ce que «__builtin_expect» ...?
__builtin_expect
J'ai cherché dans la documentation GCC et j'ai trouvé un article intitulé Other-Builtins. Vous pouvez trouver une description de «__builtin_expect» au milieu de la page. Ci-dessous le devis.
— 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.
prédiction de branche, prédiction de branche!
En d'autres termes, __builtin_expect
semble être une fonction intégrée de GCC pour indiquer la" valeur commune "que l'exp spécifié prend réellement pour la prédiction de branche.
En affichant les valeurs communes dans cette fonction intégrée de GCC, GCC sera capable de cracher le code approprié lors de la création de plusieurs branches.
Lisez uniquement la version GCC de LIKELY, UNLIKELY.
#define LIKELY(x) (__builtin_expect((x), 1))
#define UNLIKELY(x) (__builtin_expect((x), 0))
__builtin_expect
était une fonction intégrée qui indique que l'expression du premier argument prend souvent la valeur du deuxième argument.
Donc LIKELY (x) indique que l'expression x devient souvent 1 (généralement une valeur de TRUE), et UNLIKELY (x) indique que x devient souvent 0 (une valeur de FALSE).
Après tout, cruby semble améliorer la vitesse de fonctionnement au moment de la construction de GCC en insérant LIKELY (x) et UNLIKELY (x) appropriés.
Je vois.
--LIKELY, UNLIKELY est une macro qui fournit des informations auxiliaires pour la prédiction de branche au compilateur. --LIKELY utilise généralement des expressions qui sont TRUE
La valeur de LIKELY est spécifiée comme 1, mais est-ce correct si le résultat de la formule de comparaison est différent de 0?
Je pense que ce n'est pas grave si c'est comme ! Flag
avec un refus explicite, mais si vous faites une vérification NULL sur ptr
avecLIKELY (ptr)
, la valeur ne devrait pas être 1. Cela sera-t-il résolu sans aucun problème?
Au moment de la lecture, je ne sais pas comment effectuer la mesure des performances de rubis, donc je n'ai pas expérimenté depuis un moment.
Par exemple, une implémentation comme #define LIKELY (x) __builtin_expect (!! (x), 1)
a-t-elle déjà été essayée dans le passé ...?
(Non, bien sûr, cela peut être lourd au moment de passer par !!
, donc ce n'est qu'un exemple, et il semble que le résultat sera un peu flou.)