Javascript V8到底是如何优化/内联的?
我想知道是否有可能了解V8是如何优化和内联的 我创建了三个简单的函数,它们都以度为单位计算角度的正弦。我将它们全部放入闭包中,以便V8能够内联局部变量Javascript V8到底是如何优化/内联的?,javascript,optimization,google-chrome,inline,v8,Javascript,Optimization,Google Chrome,Inline,V8,我想知道是否有可能了解V8是如何优化和内联的 我创建了三个简单的函数,它们都以度为单位计算角度的正弦。我将它们全部放入闭包中,以便V8能够内联局部变量 一,。使用预先计算的常数Math.PI/180,然后执行Math.sin(x*常数) 我使用了以下代码: var test1 = (function() { var constant = Math.PI / 180; // only calculate the constant once return function(x) {
一,。使用预先计算的常数
Math.PI/180
,然后执行Math.sin(x*常数)
我使用了以下代码:
var test1 = (function() {
var constant = Math.PI / 180; // only calculate the constant once
return function(x) {
return Math.sin(x * constant);
};
})();
二,。动态计算常数
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);
};
})();
var test3 = (function() {
return function(x) {
return Math.sin(x * 3.141592653589793 / 180);
};
})();
三,。使用文字数字并动态计算常量
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);
};
})();
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
中内联,因为test2
和test3
每秒的操作量完全相同
另一方面,由于test1
的速度明显更快,因此划分似乎没有得到优化(即预先计算)
- 在这种情况下,如果不手动计算,为什么不预先计算常数
- 是否有可能看到V8如何精确地优化某个网页上的功能
pi/180
部分,因为在第二个和第三个函数中没有执行pi/180
。您只需将(x*pi)
除以180
(乘法具有优先权)
现在,你可能会问,为什么它不改变操作顺序,最终得到它可以优化的东西(顺便说一句,这个过程叫做重新关联)。。。毕竟,结果是等价的(a*b/c=(a*b)/c
)。数学是这么说的,对吗
数学是这么说的,但数学不使用浮点数。有了浮动,事情就更复杂了
x*pi
可以四舍五入,然后重新排序将导致不同的结果。错误可能很小,但编译器优化的首要规则是:你不能改变程序的结果。与其在某些图形代码中偏离一个像素(是的,这可能很明显),不如在一些以不幸的方式编写的数学基准上执行次优测试。要回答第二个问题,您可以看到V8使用此工具优化JS的字节码:。在Chrome中对代码进行低级调优非常棒。我不确定C风格内联的概念是否适用于JIT虚拟机。我只是在猜测,但我怀疑V8会将运行时优化应用于经常调用的函数,但这可能很难预测。@mikerobi:这可能是一个幼稚的问题-但难道不可能像某种调试工具那样简单地看到V8在编译/优化/内联过程中做了什么吗,但是我怀疑V8开发团队之外的任何人都能告诉你怎么做。例如,PyPy的JIT有大量的日志记录,他们开始构建一个工具来查看代码所经过的所有中间表示(Python字节码、JIT IR、机器码),因此理论上这些事情应该是可能的。但我想这是因为(1)实际的JIT是机器生成的,(2)它是跟踪JIT。V8目前不执行常量传播。另外,通过在循环中创建函数来惩罚V8(多次调用setup):请尝试修改后的测试用例。它消除了对新生成的闭包实例进行多次重新优化所带来的开销,并使情况更加清晰。旁注:如果有人怀疑我关于函数将给出不同结果的说法,请使用x=0.6784993546113602
,例如。我用Math.random()
找到了这个和许多其他数字。谢谢,这很有趣。这有助于进行更多的研究(比如使用一个常数(a*b)*x
)。使用pi*180*x
确实会产生不同的结果-现在test1
和test3
是相等的,但是test2
已经变慢了。我认为这可以用操作程序来解释。我将尝试在test2
中搜索pi
不再内联的原因。在这种情况下,x*(pi/180)
给出了什么?理论上,编译器现在可以拉出pi/180
。@cWalves:当我将我的初始测试与添加括号的同一测试进行比较时,似乎没有什么改进:和。这意味着浮点/运算符优先级的概念实际上不适用。神秘的。。。