优化/函数运行时v8状态码会发生什么变化?
我看到一个关于v8 Optimization的问题,这导致我在v8优化中玩了一下。 我也见过bluebird post about v8 Optimization killers。优化/函数运行时v8状态码会发生什么变化?
据V8回购,优化状态代码是在2乘法: 1,2,4,8等等(见OptimizationStatus枚举)
但是,下面的代码给了我奇怪的状态代码像17和65,只有在这些特定情况下(请参阅最后几行代码)。 有关为什么会发生这种情况的任何想法?
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);
运行该代码:
node --trace_deopt --allow-natives-syntax FILENAME.js
您可以使用my gist,如果你发现它更舒适
status
是按位标志值和代码应该看起来更像是这样的:
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'
考虑“状态码”17
或16 + 1
或〜(1 << 4) | (1 << 0)
,这意味着“kIsFunction”和“kIsOptimized”。
查看bit arrays的一般操作 - 以及为什么在代码中显示的条件使用&
。
%GetOptimizationStatus
已更新为返回一组按位标志而不是单个值,并且文章Optimization Killers已过期。可用的状态信息也略有变化。
要访问新值,需要获取返回值的二进制表示形式。现在,例如,如果返回65
,二进制表示如下:
65₁₀ = 000001000001₂
每个二进制数位用作具有以下含义的布尔:
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
因此,65
表示该功能是功能和解释(这意味着它是而不是在查询其状态时进行了优化)。
在JavaScript中访问这些值,只需使用位AND运算符,看看是否值不为零:
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");
...
等。这里的关键是不止一个条件可以评估为真。
您知道GetOptimizationStatus的返回值何时更新? – liuyanghejerry
@liuyanghejerry - 我不确定,但肯定会返回一组按位标志(在这个答案中提到)在58和更高版本。 –
它们是位域,由多个标志组成。你所描述的“状态代码”是访问返回值中个别标志的掩码。 – Bergi
另外,请注意,“优化杀手”文件已过时,因为它谈到了已经退役的“曲轴”编译器。从Chrome M59/Node.js 8.3开始,V8使用“Turbofan”,它可以优化一切。(有些构造总是比其他构造慢,但是Turbofan的设计永远不会因为任何原因拒绝优化整个函数。) – jmrk