function add(x, y) {
return x + y;
}
console.time("time1");
for (var i = 0; i < 90000000; ++i) {
add(1, 2);
add('a','b');
}
console.timeEnd("time1");
function addText(x, y) {
return x + y;
}
function addNumber(x, y) {
return x + y;
}
console.time("time2");
for (var i = 0; i < 90000000; ++i) {
addNumber(1, 2);
addText('a','b');
}
console.timeEnd("time2");
结果是: 时间 1:1481 毫秒, time2: 102ms,
我在 nodejs 上运行这个测试,但我不知道为什么第一个测试比第二个慢。
最佳答案
这是因为参数类型更改导致引擎盖下发生了去优化。要知道这一点,我们必须知道优化 V8 做了什么:
内联
这是一项重要的优化,对于性能提升至关重要。它用函数体代替函数调用以加速执行。如果一个函数的大小很小,它将被内联。这假设在函数调用中,参数是固定的。
去优化
V8 在某些假设下进行优化。如果错误,它必须撤消那些优化,以便它能够正确运行代码。去优化是不好的,因为它需要时间并且被替换的代码性能较低。
要查看此操作,请使用选项运行代码 --trace_opt
--trace_opt_stats
--trace_deopt
--trace-内联
[deoptimize context: cbf30f14679]
[marking addText 0xcbf30fc5ca0 for recompilation, reason: small function, ICs with typeinfo: 1/1 (100%)]
[optimizing: addText / cbf30fc5ca1 - took 0.058, 0.092, 0.000 ms]
Compiled: 1 functions with 42 byte source size in 0.150000ms.
[marking addNumber 0xcbf30fc5ce8 for recompilation, reason: small function, ICs with typeinfo: 1/1 (100%)]
[optimizing: addNumber / cbf30fc5ce9 - took 0.019, 0.033, 0.000 ms]
Compiled: 2 functions with 84 byte source size in 0.202000ms.
[marking 0x2c9408e1b3d0 for recompilation, reason: not much type info but very hot, ICs with typeinfo: 1/12 (8%)]
Inlined addNumber called from .
Inlined addText called from .
[optimizing: / 2c9408e1b3d1 - took 0.131, 0.229, 0.000 ms]
Compiled: 3 functions with 898 byte source size in 0.562000ms.
time1: 126ms
**** DEOPT: at bailout #11, address 0x0, frame size 192
[deoptimizing: begin 0x2c9408e1b3d1 @11]
translating => node=111, height=32
0x7fff72081080: [top + 104] <- 0x2c9408e1b4e9 ; [sp + 32] 0x2c9408e1b4e9 <an Object>
0x7fff72081078: [top + 96] <- 0x58df1704121 <undefined> ; literal
0x7fff72081070: [top + 88] <- 0x58df1704121 <undefined> ; literal
0x7fff72081068: [top + 80] <- 0x58df1704121 <undefined> ; literal
0x7fff72081060: [top + 72] <- 0x58df1704121 <undefined> ; literal
0x7fff72081058: [top + 64] <- 0x58df1704121 <undefined> ; literal
0x7fff72081050: [top + 56] <- 0x23522b3122be ; caller's pc
0x7fff72081048: [top + 48] <- 0x7fff720810b0 ; caller's fp
0x7fff72081040: [top + 40] <- 0x2c9408e1b0d9; context
0x7fff72081038: [top + 32] <- 0x2c9408e1b3d1; function
0x7fff72081030: [top + 24] <- 0x2c9408e1b389 ; [sp + 40] 0x2c9408e1b389 <JS Function add>
0x7fff72081028: [top + 16] <- 0x2c9408e1b2f9 ; [sp + 48] 0x2c9408e1b2f9 <JS Function addText>
0x7fff72081020: [top + 8] <- 0x2c9408e1b341 ; [sp + 56] 0x2c9408e1b341 <JS Function addNumber>
0x7fff72081018: [top + 0] <- 0 ; rbx (smi)
[deoptimizing: end 0x2c9408e1b3d1 => node=111, pc=0x23522b364aa0, state=NO_REGISTERS, alignment=no padding, took 0.076 ms]
[removing optimized code for: ]
[marking add 0x2c9408e1b388 for recompilation, reason: small function, ICs with typeinfo: 1/1 (100%)]
[optimizing: add / 2c9408e1b389 - took 0.013, 0.024, 0.000 ms]
Compiled: 4 functions with 939 byte source size in 0.599000ms.
[marking 0x2c9408e1b3d0 for recompilation, reason: hot and stable, ICs with typeinfo: 2/12 (16%)]
Inlined addNumber called from .
Inlined addText called from .
Inlined add called from .
Inlined add called from .
[optimizing: / 2c9408e1b3d1 - took 0.100, 0.194, 0.000 ms]
Compiled: 5 functions with 1753 byte source size in 0.893000ms.
time2: 1759ms
第一个循环由于参数更改而失去优化并且运行时间更长。这不能用缓存命中/未命中来解释,因为没有读/写。
来源: http://floitsch.blogspot.in/2012/03/optimizing-for-v8-inlining.html
关于V8 上的 JavaScript 测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20039587/