【问题标题】:Why cube is faster than square为什么立方体比正方形快
【发布时间】:2016-07-10 17:41:08
【问题描述】:

这是我写的:

  var max = 0xffffff * 4;
  var step = 1 / max;
  function cube() {
    var result = 0.;
    for (var x = 0.; x < 1; x += step) {
      result += x * x * x;
    }
    return result;
  }
  function mul() {
    var result = 0.;
    for (var x = 0.; x < 1; x += step) {
      result += x * x;
    }
    return result;
  }
  function go() {
    var r = '';
    r += cube() + ' \n';
    r += mul() + ' \n';
    alert(r);
  }

并在 Chrome 分析器中查看结果:

mul: 106ms 
cube: 87ms

这怎么可能?

【问题讨论】:

  • go()中交换调用顺序是否也更快?
  • 与其使用 Chrome 分析器,不如尝试使用 Performance API developer.mozilla.org/en-US/docs/Web/API/Performance/now
  • 我得到了相同的结果,但如果我先执行mul() 然后cube() 我得到mul() 更快。它发生在其他人身上吗?
  • chromium.googlesource.com/v8/v8.git 浏览了当前的V8 源代码(Chrome 的JS 引擎) - 发现:a) 解释器或指令选择器没有将x*x*x 收缩为pow(x,3)exp(n*log(x)) b) Float64Mul 操作码生成非常复杂,并带有特殊情况处理(+/-0.5、1.0、...)和依赖于平台/架构的修饰,因此这个 Q 将是一个非常难以破解的坚果。

标签: javascript performance


【解决方案1】:

在某些浏览器上,javascript 以解释的形式开始,而 JIT 在后台对其进行编译。 javascript 编译完成后,它开始运行得更快。

【讨论】:

【解决方案2】:

你的断言是完全错误的。 cube 不比 mul 快,您的示例并不能证明这一点。

事实上,发生的情况是 Javascript 的内部执行比实际的乘法需要更多的时间,导致 mul 和 cube 的时间非常相似。我在一个循环中运行了这两个函数,只是为了增加差异,并且分析器显示 20219 与 20197,这是微不足道的。顺便说一句,立方体在这里是“较慢”的。

此外,这种分析方法不起作用,因为 Chrome 和 Firefox 在循环内进行数学运算之前都进行了很多优化。您认为的循环很可能使用缓存值,甚至优化知道返回相同结果的数学函数。

这是我使用的代码:

<script>
 var max = 0xffffff * 4;
  var step = 1 / max;
  function cube() {
    var result = 0.;
    for (var x = 0.; x < 1; x += step) {
      result += x * x * x;
    }
    return result;
  }
  function mul() {
    var result = 0.;
    for (var x = 0.; x < 1; x += step) {
      result += x * x;
    }
    return result;
  }
  function go() {
    var s='';
    for (var i=0; i<100; i++) {
        s+=cube();
        s+=mul();
    }
    console.log(s);
  }
  go();
</script>

另外,仅供参考,请在此处观看视频:https://fosdem.org/2016/schedule/event/mozilla_benchmarking_javascript_tips/ 一个 Firefox 专家解释了为什么微基准测试并没有多大意义。

【讨论】:

  • 在 Chrome 49 中,我所看到的情况并非如此 - mul 始终比 cube 慢。不同浏览器中的不同结果 - 这似乎与 Chrome 正在进行的特定优化有关 - 请参阅 Q 下的评论链。你能展示你是如何构建分析循环的吗? EG 因为它是一个纯粹基于数学的函数,如果你不使用返回值,它可能会优化整个计算等。
  • 我只能假设它与您的计算机有关。您是否尝试过交换功能?也许这与哪个是第一个或什么有关。无论如何,在您的屏幕截图中,这两个函数之间的时间差非常大。
  • 是的 - 根据问题下的 cmets,函数顺序没有区别。看起来它确实是对某些 CPU 等的 Chrome 优化。开始认为我们需要 Chrome/V8 工程师来解决这个问题 - 这本身在 SO 上并不是未知的......
  • 也许这会对您的任务有所帮助:stackoverflow.com/questions/18476402/…(如何禁用 V8 的优化编译器)
  • 我也可以确认@JamesThorpe 的发现,在我的机器上,cube 在这个基准测试中运行得更快
【解决方案3】:

这可能是因为由于您的所有数字都低于 1,cube 函数添加的数字小于正方形,并且(我不确定这是否真的是这样工作的)因此花费的时间更少。这只是一个猜测。而且由于数字太小,这也可能是由于精度不足。此外,我用超过 1 的数字进行了测试,它们的立方体速度较慢。

【讨论】:

  • 你的猜测是错误的,数字的“大小”无关紧要,尾数总是充满数字,无论“大小”如何。大多数操作都是在尾数上执行的。
【解决方案4】:

也许优化器决定其中一个可以使用向量指令执行,而另一个使用普通的旧 fmul。我推测 'square' 使用 fmul,而 cube 使用向量指令 mulpd,它可以在一条指令中乘以多达 4 个双精度数。我添加了一个“四边形”,它做了 4 次乘法,它的时间非常接近立方体。但是当我去“五”时,它的速度比正方形慢。这是向量指令用于立方体和四边形的一些间接证据。

在平板电脑上查看英特尔 cpu 与 arm 上的结果会很有趣。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多