V8如何优化/内联?

pim*_*vdb 19 javascript optimization google-chrome v8 inline

我想知道是否有可能获得V8如何优化和内联的知识.

我创建了三个简单的测试函数,它们都以度为单位计算角度的正弦值.我将它们全部放入闭包中,以便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);
  };
})();
Run Code Online (Sandbox Code Playgroud)

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);
  };
})();
Run Code Online (Sandbox Code Playgroud)

3.使用文字数字并动态计算常数.

var test3 = (function() {
  return function(x) {
    return Math.sin(x * 3.141592653589793 / 180);
  };
})();
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,结果如下:

test1 - 25,090,305 ops/sec
test2 - 16,919,787 ops/sec
test3 - 16,919,787 ops/sec
Run Code Online (Sandbox Code Playgroud)

它看起来像pi没有得到内联在test2test2test3导致量是相同的每秒操作的.

另一方面,划分似乎没有被优化(即预先计算),因为test1明显更快.

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

小智 7

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

严格来说,它不能对pi / 180零件进行常数折叠,因为你没有pi / 180在第二和第三个函数中做.你刚才划分(x * pi)180(乘法的优先级).

现在,您可能会问为什么它不会改变操作的顺序以最终可以优化(此过程称为重新关联,顺便说一下)......毕竟,结果是等效的(a * b / c = (a * b) / c).数学如此说,对吧?

好吧,数学说的是,但数学不使用浮点数.随着花车,事情变得更加复杂.x * pi可以舍入,然后重新排序将导致不同的结果.错误可能很小,但仍然是编译器优化的主要规则是:你不能改变程序的结果.在一些数学基准测试中,以一种不幸的方式执行,而不是在一些图形代码中被像素关闭(是的,这可能是显而易见的),这样做会更好.