В чем разница между использованием '%OptimizeFunctionOnNextCall()'
отдельно и использованием '%OptimizeFunctionOnNextCall()'
в сочетании с '%PrepareFunctionForOptimization()
'?
function test() {
// some code here to optimize
}
%OptimizeFunctionOnNextCall(test);
test();
// ./d8 test.js --allow-natives-syntax --trace-turbo --trace-turbo-path turbo_out --trace-turbo-filter test
function test() {
// some code here to optimize
}
%PrepareFunctionForOptimization(test);
test();
%OptimizeFunctionOnNextCall(test);
test();
// ./d8 test.js --allow-natives-syntax --trace-turbo --trace-turbo-path turbo_out --trace-turbo-filter test
function test() {
// some code here to optimize
}
%OptimizeFunctionOnNextCall(test);
test(); // This call will trigger the optimization of the test function
Этот подход хорошо работает, если функция уже находится в состоянии, которое можно оптимизировать (например, она вызывалась достаточное количество раз, чтобы собрать обратную связь о типе).
function test() {
// some code here to optimize
}
%PrepareFunctionForOptimization(test);
test(); // This call prepares the function and gathers feedback
%OptimizeFunctionOnNextCall(test);
test(); // This call will trigger the optimization of the test function
Этот подход более надежен, особенно если функция, возможно, была деоптимизирована или еще не собрала достаточно отзывов о типах. %PrepareFunctionForOptimization
гарантирует, что функция находится в чистом состоянии и готова к оптимизации при следующем вызове.
TL;DR: %PrepareFunctionForOptimization
гарантирует, что функция собирает обратную связь.
Чтобы компиляция Turbofan/Maglev принесла какую-либо пользу, функция должна быть запущена несколько раз и собрать обратную связь о том, какие ее входные данные. Эта обратная связь собирается в так называемый «вектор обратной связи». В целях экономии памяти векторы обратной связи лениво выделяются только после того, как функция была выполнена несколько раз (где «несколько раз» определяется флагом infection_count_for_feedback_allocation; в настоящее время 8).
%PrepareFunctionForOptimization
принудительно выделяет вектор обратной связи данной функции (см. ее реализацию), тем самым гарантируя, что, начиная со следующего вызова, она будет собирать обратную связь.
Таким образом, обычный процесс написания модульных тестов JavaScript для V8 обычно выглядит следующим образом:
%PrepareFunctionForOptimization(foo); // Allocates feedback vector
foo(); // Collect feedback
%OptimizeFunctioOnNextCall(foo); // Trigger optimization on next call, which will
foo(); // optimize based on the feedback collected so far.
Обратите внимание, что использование %OptimizeFunctionOnNextCall
без предварительного вызова %PrepareFunctionForOptimization
должно привести к сбою (если вы не используете определенные флаги, такие как --fuzzing
), потому что это почти никогда не то, что вы хотите: оптимизация без обратной связи очень редко бывает полезной.
Если функция уже была деоптимизирована, это означает, что она уже была оптимизирована ранее, а это означает, что у нее есть вектор обратной связи, и поэтому
%PrepareFunctionForOptimization
должна быть неактивной. Обратите внимание, что%PrepareFunctionForOptimization
не очищает существующую обратную связь: она выделяет вектор обратной связи, если у функции его еще нет, и ничего не делает в противном случае.