2017-10-14 4 views
5

J'ai vu une question à propos de v8 Optimization qui m'a amené à jouer un peu avec l'optimisation v8. J'ai également vu bluebird post à propos de v8 Optimization killers.Qu'arrive-t-il au code d'état v8 lors de l'exécution de l'optimisation/de la fonction?

Selon repo v8, codes d'état d'optimisation sont en multiplications de 2: 1,2,4, 8 et ainsi de suite (voir OptimizationStatus ENUM)

Cependant, le code suivant m'a donné des codes d'état étranges comme 17 et 65, et seulement dans ces cas spécifiques (voir les dernières lignes de code). Des idées sur pourquoi cela se passe-t-il?

function adder(a, b) { 
    return new Function('a', 'b', 'return b%2 ? a + b : b%3 ? a - b : b%5 ? b/a : a * b')(a, b); 
} 
function addereval(a, b) { 
    return eval('b%2 ? a + b : b%3 ? a - b : b%5 ? b/a : a * b'); 
} 

function printStatus(fn) { 
    var status = %GetOptimizationStatus(fn) 
    switch (status) { 
     case 1: console.log(fn.name, "function is optimized"); break; 
     case 2: console.log(fn.name, "function is not optimized"); break; 
     case 3: console.log(fn.name, "function is always optimized"); break; 
     case 4: console.log(fn.name, "function is never optimized"); break; 
     case 6: console.log(fn.name, "function is maybe deoptimized"); break; 
     case 7: console.log(fn.name,"Function is optimized by TurboFan"); break; 
     default: console.log(fn.name, "Unknown optimization status: ", status); break; 
    } 
} 
printStatus(adder); 
printStatus(addereval); 


for(let i = 0; i < 263; i++) { 
    adder(1, 2); 
} 
console.log('\n', '==== adder after invocation - result is on node v8.2.1 17 or 65 on node v8.7.0 ==='); 
printStatus(adder); 

addereval(1, 2); 
console.log('\n', '==== addereval after invocation - result is 65 ==='); 
printStatus(addereval); 

Exécutez ce code avec:

node --trace_deopt --allow-natives-syntax FILENAME.js 

Vous pouvez utiliser my gist si vous trouvez plus confortable

+2

Ce sont des champs de bits composés de plusieurs drapeaux. Ce que vous décrivez comme "codes d'état" sont les masques permettant d'accéder à l'indicateur individuel dans la valeur de retour. – Bergi

+2

Notez également que le document "Optimization Killers" est obsolète, car il parle du compilateur "Crankshaft", qui a été retiré. A partir de Chrome M59/Node.js 8.3, V8 utilise "Turbofan", qui permet d'optimiser tout.(Certaines constructions seront toujours plus lentes que d'autres, mais Turbofan a été conçu pour ne jamais refuser l'optimisation d'une fonction entière pour une raison quelconque.) – jmrk

Répondre

3

status est une valeur de drapeau bitwise et le code devrait ressembler à ceci:

var status = GetOptimizationStatus(fn); 
if ((status & (1 << 0)) { 
    console.log(fn.name, "kIsFunction"); 
} 
if ((status & (1 << 1)) { 
    console.log(fn.name, "kNeverOptimize"); 
} 
// etc .. can be 'true' for several different combinations; 
// most notably, many different status will also include 'kIsFunction' 

Considérons un "code d'état" de 17 ~ ou ~ 16 + 1 ~ ou ~ (1 << 4) | (1 << 0) ~ ce qui signifie ~ "kIsFunction" et "kIsOptimized". Voir le bit arrays pour la manipulation générale - et pourquoi l'utilisation de & dans les conditions indiquées dans le code.

4

%GetOptimizationStatus a été mis à jour pour renvoyer un ensemble de drapeaux au lieu d'une seule valeur, et l'article Optimization Killers est obsolète. Les informations d'état disponibles ont également été légèrement modifiées.

Pour accéder à la nouvelle valeur, vous devez prendre la représentation binaire de la valeur renvoyée. Maintenant, par exemple, si 65 est retourné, la représentation binaire est la suivante:

65₁₀ = 000001000001₂ 

Chacun agit binaires chiffres comme un booléen avec la signification suivante:

0 0 0 0 0 1 0 0 0 0 0 1 
┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ 
│ │ │ │ │ │ │ │ │ │ │ └─╸ is function 
│ │ │ │ │ │ │ │ │ │ └───╸ is never optimized 
│ │ │ │ │ │ │ │ │ └─────╸ is always optimized 
│ │ │ │ │ │ │ │ └───────╸ is maybe deoptimized 
│ │ │ │ │ │ │ └─────────╸ is optimized 
│ │ │ │ │ │ └───────────╸ is optimized by TurboFan 
│ │ │ │ │ └─────────────╸ is interpreted 
│ │ │ │ └───────────────╸ is marked for optimization 
│ │ │ └─────────────────╸ is marked for concurrent optimization 
│ │ └───────────────────╸ is optimizing concurrently 
│ └─────────────────────╸ is executing 
└───────────────────────╸ topmost frame is turbo fanned 

Ainsi, 65 signifie que la fonction est une fonction et est interprétée (ce qui signifie que n'est pas optimisé au moment de l'interrogation de son état).

Pour accéder à ces valeurs en JavaScript, utilisez simplement le niveau du bit opérateur et si la valeur est non nulle:

var status = %GetOptimizationStatus(fn); 

if (status & 1) console.log("function is function"); 
if (status & 2) console.log("function is never optimized"); 
if (status & 4) console.log("function is always optimized"); 
if (status & 8) console.log("function is maybe deoptimized"); 
if (status & 16) console.log("function is optimized"); 
if (status & 32) console.log("function is optimized by TurboFan"); 
if (status & 64) console.log("function is interpreted"); 
... 

Et ainsi de suite. L'aspect clé ici est que plus d'une de ces conditions peut être vraie.

+0

Savez-vous quand la valeur de retour de GetOptimizationStatus est-elle mise à jour? – liuyanghejerry

+1

@liuyanghejerry - Je ne suis pas sûr exactement, mais il retourne définitivement un ensemble de drapeaux au niveau du bit (comme mentionné dans cette réponse) en 58 et plus tard. –