为什么 "Self Time" 在一个有效的空函数中如此之高?
Why is "Self Time" so high in an effectively empty function?
我有一个计算量很大的函数,它在循环中被调用了很多次:
function func() { // Some fluff
for(let i = 0; i < 1000; i++) {
i *= 10
i /= 10
}
}
function run() {
for(let i = 0; i < 100000; i++) {
func()
}
}
run()
当我使用 Chrome 的 DevTools 分析这个脚本时,我得到了这个:
run
在 1015 毫秒的总时间中有 887 毫秒的自身时间,尽管它唯一做的就是重复调用 func
.
我希望 func
有大部分的自我时间,因为它是叶函数。
这是为什么?
(此处为 V8 开发人员。)
the function was automatically inlined after some time when it became "hot".
正确。一旦 run
被优化,优化器决定将 func
内联到其中。之后,就profiler而言,所有的时间都花在了run
.
(为了验证这一点,运行 d8
或 node
中的片段与 --trace-turbo-inlining
。)
旁注:在这种情况下,获得 run
的优化代码比平时花费的时间要长一些,因为该函数永远不会 returns 再次被调用(这是切换到优化代码的最佳时间)。系统等待它发生,当它没有发生时,run
最终被“堆栈替换”。这是一种典型模式,经常出现在小型测试和基准测试中,很少出现在实际代码中。
Doesn't this just show that performing 100000 function calls are more expensive than a 1000 iterations of two simple arithmetic operations -- which makes sense?
不,它没有显示;这只是一个人如何被这个微基准误导的一种特殊方式。
就个人而言,我有点失望地看到(使用 --print-opt-code
)编译器没有意识到 i *= 10; i /= 10;
是空操作,可以完全删除。那将是在这里被误导的另一种好方法。哦,好吧,可能有一些原因导致编译器更难确定该转换既适用又安全...
我有一个计算量很大的函数,它在循环中被调用了很多次:
function func() { // Some fluff
for(let i = 0; i < 1000; i++) {
i *= 10
i /= 10
}
}
function run() {
for(let i = 0; i < 100000; i++) {
func()
}
}
run()
当我使用 Chrome 的 DevTools 分析这个脚本时,我得到了这个:
run
在 1015 毫秒的总时间中有 887 毫秒的自身时间,尽管它唯一做的就是重复调用 func
.
我希望 func
有大部分的自我时间,因为它是叶函数。
这是为什么?
(此处为 V8 开发人员。)
the function was automatically inlined after some time when it became "hot".
正确。一旦 run
被优化,优化器决定将 func
内联到其中。之后,就profiler而言,所有的时间都花在了run
.
(为了验证这一点,运行 d8
或 node
中的片段与 --trace-turbo-inlining
。)
旁注:在这种情况下,获得 run
的优化代码比平时花费的时间要长一些,因为该函数永远不会 returns 再次被调用(这是切换到优化代码的最佳时间)。系统等待它发生,当它没有发生时,run
最终被“堆栈替换”。这是一种典型模式,经常出现在小型测试和基准测试中,很少出现在实际代码中。
Doesn't this just show that performing 100000 function calls are more expensive than a 1000 iterations of two simple arithmetic operations -- which makes sense?
不,它没有显示;这只是一个人如何被这个微基准误导的一种特殊方式。
就个人而言,我有点失望地看到(使用 --print-opt-code
)编译器没有意识到 i *= 10; i /= 10;
是空操作,可以完全删除。那将是在这里被误导的另一种好方法。哦,好吧,可能有一些原因导致编译器更难确定该转换既适用又安全...