是什么导致这个函数运行速度变慢?

2024-01-11

我一直在尝试做一个实验,看看函数中的局部变量是否存储在堆栈上。

所以我写了一些性能测试

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 倍。

Example:

> 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 倍)性能的来源是什么?

附言。由于它似乎仅在某些环境中工作,因此请编写您用来测试它的环境。

我的是:

操作系统:Ubuntu 14.04
节点 v0.10.37
Chrome 43.0.2357.134(官方版本)(64 位)

/Edit
在 Firefox 39 上,无论顺序如何,每次测试都需要约 5500 毫秒。它似乎只发生在特定的引擎上。

/Edit2
将函数内联到测试函数使其始终同时运行。
如果函数参数始终是相同的函数,是否可能存在内联函数参数的优化?


一旦你打电话test有两种不同的功能fn()它内部的调用点变得超态,V8 无法内联它。

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

因为V8无法内联fn()callsite 无法对您的代码应用各种优化。如果你查看你的代码IRHydra http://mrale.ph/irhydra/2/#gist:5bb357ed94154fbc5391(为了方便起见,我将编译工件上传到要点)您会注意到第一个优化版本test(当它专门用于fn = straight)有一个完全空的主循环。

V8刚刚内联straight and removed您希望通过死代码消除优化进行基准测试的所有代码。在旧版本的 V8(而不是 DCE)上,V8 只会通过 LCM 将代码提升到循环之外 - 因为代码是完全循环不变的。

When straight未内联的 V8 无法应用这些优化 - 因此存在性能差异。较新版本的 V8 仍将 DCE 应用到straight and inversed他们自己把它们变成空函数

所以性能差异并不是那么大(大约 2-3 倍)。较旧的 V8 对于 DCE 不够积极,这会在内联和非内联情况之间表现出更大的差异,因为内联情况的峰值性能完全是积极的循环不变代码运动 (LICM) 的结果。

在相关说明中,这说明了为什么基准永远不应该这样编写 - 因为它们的结果没有任何用处,因为您最终测量的是空循环。

如果您对多态性及其在 V8 中的影响感兴趣,请查看我的帖子“单态是怎么回事” http://mrale.ph/blog/2015/01/11/whats-up-with-monomorphism.html(“并非所有缓存都相同”部分讨论了与函数调用相关的缓存)。我还建议阅读我的一篇关于微基准测试危险的演讲,例如最近的《JS 基准测试》 http://mrale.ph/talks/goto2015/#/2015 年 GOTO 芝加哥演讲(video https://www.youtube.com/watch?v=g0ek4vV7nEA) - 它可能会帮助您避免常见的陷阱。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是什么导致这个函数运行速度变慢? 的相关文章

随机推荐