Как именно оптимизатор V8/встроенный?
Мне интересно, можно ли узнать, как именно 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);
};
})();
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
, поскольку test2
и test3
приводят к точному количеству операций в секунду.
С другой стороны, деление, кажется, не оптимизировано (т.е. не вычисляется), так как test1
значительно быстрее.
- Почему константа не вычисляется заранее, если вы не делаете это вручную в этом случае?
- Можно ли увидеть, как V8 точно оптимизирует функции на определенной веб-странице?
Ответы
Ответ 1
Уверенное предположение о вашем первом вопросе:
Строго говоря, он не может постоянно сгибать часть pi / 180
, потому что вы не выполняете pi / 180
во второй и третьей функции. Вы просто разделите (x * pi)
на 180
(приоритет имеет умножение).
Теперь вы можете спросить, почему он не меняет порядок операций, чтобы завершить что-то, что он может оптимизировать (этот процесс называется пересоединением, кстати)... в конце концов, результат эквивалентен (a * b / c = (a * b) / c
). Математика так говорит, верно?
Ну, математика так говорит, но математика не использует числа с плавающей запятой. С поплавками все сложнее. x * pi
может быть округлено, а затем переупорядочение приведет к другому результату. Ошибки, вероятно, будут крошечными, но все же ведущим правилом оптимизации компилятора является: вы не должны изменять результат программы. Лучше выполнять субоптимальное на нескольких математических тестах, написанных неудачным способом, чем отключение пикселя (да, это может быть заметно) в некоторых графических кодах.
Ответ 2
Чтобы ответить на второй вопрос, вы можете увидеть байт-код, который V8 оптимизировал ваш JS для использования этого инструмента: http://mrale.ph/irhydra/2/. Это фантастика для низкоуровневой настройки кода в Chrome.