【问题标题】:How exactly does V8 optimize/inline?V8 究竟如何优化/内联?
【发布时间】:2011-12-23 04:00:48
【问题描述】:

我想知道是否有可能了解 V8 究竟是如何优化和内联事物的。

我创建了三个简单的test functions,它们都以度为单位计算角度的正弦值。我将它们全部放入闭包中,以便 V8 应该能够内联局部变量。


1。使用预先计算的常量Math.PI / 180,然后执行Math.sin(x * constant)

我使用了这个代码:

var test1 = (function() {
  var constant = Math.PI / 180; // only calculate the constant once

  return function(x) {
    return Math.sin(x * constant);
  };
})();

2。即时计算常数。

var test2 = (function() {
  var pi = Math.PI; // so that the compiler knows pi cannot change
                    // and it can inline it (Math.PI could change
                    // at any time, but pi cannot)

  return function(x) {
    return Math.sin(x * pi / 180);
  };
})();

3。使用文字数字并即时计算常数。

var test3 = (function() {
  return function(x) {
    return Math.sin(x * 3.141592653589793 / 180);
  };
})();

出乎意料的是,结果如下:

test1 - 25,090,305 ops/sec
test2 - 16,919,787 ops/sec
test3 - 16,919,787 ops/sec

看起来pi 确实在test2 中内联,因为test2test3 导致每秒的操作量完全相同。

另一方面,除法似乎没有优化(即预先计算),因为test1 明显更快。

  • 在这种情况下,如果您不手动执行此操作,为什么不预先计算常量?
  • 是否可以看到 V8 在某个网页上究竟是如何优化功能的?

【问题讨论】:

  • 我不确定 C 风格内联的概念是否适用于 JITed 虚拟机。我只是推测,但我怀疑 V8 将运行时优化应用于经常调用的函数,但可能很难预测。
  • @mikerobi:这可能是一个幼稚的问题 - 但不能像某种调试工具一样简单地查看 V8 在编译/优化/内联期间所做的事情吗?
  • 这可能是可能的,但我怀疑 V8 开发团队以外的任何人都可以告诉你如何做。
  • 好吧,例如 PyPy 的 JIT 具有广泛的日志记录,他们开始构建一个工具来查看代码经过的所有中间表示(Python 字节码、JIT IR、机器代码),所以这样的事情应该是可能的理论上。但我想这会变得更容易,因为 (1) 实际的 JIT 是机器生成的,(2) 它是一个跟踪 JIT。
  • V8 目前执行持续传播。您还可以通过在循环中创建函数来惩罚 V8(多次调用设置):尝试修改后的测试用例 jsperf.com/optimizing-v8/2。它消除了新生成的闭包实例的多次重新优化引入的开销,并使画面更加清晰。

标签: javascript optimization google-chrome inline v8


【解决方案1】:

要回答您的第二个问题,您可以查看 V8 使用此工具优化您的 JS 的字节码:http://mrale.ph/irhydra/2/。它非常适合在 Chrome 中进行代码的低级调优。

【讨论】:

    【解决方案2】:

    对您的第一个问题的有根据的猜测:

    严格来说,它不能常量折叠pi / 180 部分,因为你没有在第二个和第三个函数中做pi / 180。您只需将(x * pi) 除以180(乘法优先)。

    现在,您可能会问为什么它不改变操作顺序以得到可以优化的东西(这个过程称为重新关联,顺便说一句)......毕竟,结果是等价的(@ 987654328@)。数学是这样说的,对吧?

    好吧,数学是这样说的,但数学不使用浮点数。有了浮点数,事情就变得更复杂了。 x * pi 可能会被四舍五入,然后重新排序会导致不同的结果。错误可能很小,但编译器优化的主要规则仍然是:你不能改变程序的结果。最好在以不幸方式编写的一些数学基准测试中执行次优,而不是在某些图形代码中偏离一个像素(是的,这可能很明显)。

    【讨论】:

    • 旁注,以防有人怀疑我声称这些函数会给出不同的结果:例如,尝试使用x = 0.6784993546113602。我用Math.random() 找到了这个号码和许多其他号码。
    • 谢谢,这很有趣。它可以进行更多研究(例如使用常量 (a * b) * x)。
    • 使用pi * 180 * x 确实会产生不同的结果——现在test1test3 相等,但test2 变慢了。我认为这可以用运算符优先级来解释。我将尝试在test2 中寻找pi 不再被内联的原因。 jsperf.com/optimizing-v8-2
    • 在这种情况下,x * (pi / 180) 给出了什么?编译器理论上可以现在拉出pi / 180
    • @cwolves:当我比较我的初始测试和添加了括号的相同测试时,似乎几乎没有改进:jsperf.com/optimizing-v8/2jsperf.com/optimizing-v8/3。这意味着浮点/运算符优先的想法实际上是适用的。神秘...
    猜你喜欢
    • 2016-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    • 2018-06-03
    相关资源
    最近更新 更多