我一直在尝试进行实验,以查看函数中的局部变量是否存储在堆栈中。

所以我写了一点性能测试

function test(fn, times){
    var i = times;
    var t = Date.now()
    while(i--){
        fn()
    }
    return Date.now() - t;
}
ene
function straight(){
    var a = 1
    var b = 2
    var c = 3
    var d = 4
    var e = 5
    a = a * 5
    b = Math.pow(b, 10)
    c = Math.pow(c, 11)
    d = Math.pow(d, 12)
    e = Math.pow(e, 25)
}
function inversed(){
    var a = 1
    var b = 2
    var c = 3
    var d = 4
    var e = 5
    e = Math.pow(e, 25)
    d = Math.pow(d, 12)
    c = Math.pow(c, 11)
    b = Math.pow(b, 10)
    a = a * 5
}

我希望得到逆函数的工作要快得多。相反,出现了惊人的结果。

在测试其中一个功能之前,它的运行速度比测试第二个功能后的运行速度快10倍。

例子:
> test(straight, 10000000)
30
> test(straight, 10000000)
32
> test(inversed, 10000000)
390
> test(straight, 10000000)
392
> test(inversed, 10000000)
390

以替代顺序测试时,行为相同。
> test(inversed, 10000000)
25
> test(straight, 10000000)
392
> test(inversed, 10000000)
394

我已经在Chrome浏览器和Node.js中对其进行了测试,但我完全不知道为什么会发生这种情况。
效果一直持续到我刷新当前页面或重新启动Node REPL。

如此显著(约差12倍)的根源可能是什么?

PS。由于它似乎仅在某些环境下有效,因此请编写您要用于测试的环境。

我的是:

操作系统:Ubuntu 14.04
节点v0.10.37
Chrome 43.0.2357.134(正式版)(64位)

/编辑
在Firefox 39上,每次测试大约花费5500毫秒,而与顺序无关。它似乎仅在特定引擎上发生。

/编辑2
将函数内联到测试函数可以使其始终在同一时间运行。
如果始终是同一函数,是否有可能优化内联函数参数?

最佳答案

一旦使用两个不同的函数test调用站点来调用fn(),它就会变得很大,并且V8无法对其进行内联。

V8中的函数调用(与方法调用o.m(...)相对)带有一个元素内联缓存,而不是真正的多态内联缓存。

由于V8无法在fn()调用站点内联,因此无法对您的代码进行各种优化。如果您查看IRHydra中的代码(为了方便起见,我已将编译工件上传到gist),您会注意到test的第一个优化版本(当它专门用于fn = straight时)具有完全空白的主循环。

javascript - 是什么使此功能运行慢得多?-LMLPHP

V8刚刚内联了straight,删除了您希望通过Dead Code Elimination优化进行基准测试的所有代码。在较旧版本的V8而不是DCE上,V8会通过LICM将代码提升到循环之外-因为代码完全是循环不变的。

当不内联straight时,V8无法应用这些优化-因此性能有所不同。较新版本的V8仍将DCE应用于straightinversed本身,将它们转换为空函数

javascript - 是什么使此功能运行慢得多?-LMLPHP

因此性能差异不是很大(大约2-3倍)。较旧的V8使用DCE不够积极-内联和非内联案例之间的差异更大,这是因为内联案例的峰值性能仅是主动循环不变代码运动(LICM)的结果。

在相关说明中,这说明了为什么决不能这样写基准-因为最终测量空循环时它们的结果没有任何用处。

如果您对多态及其对V8的影响感兴趣,请查看我的"What's up with monomorphism"帖子(“并非所有的缓存都相同”一节中讨论了与函数调用相关的缓存)。我还建议您通读我的有关微基准测试的危险性的演讲之一,例如GOTO Chicago 2015("Benchmarking JS")的最新video演讲-它可以帮助您避免常见的陷阱。

关于javascript - 是什么使此功能运行慢得多?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31698296/

10-13 02:15