Вход

Просмотр полной версии : fix leaking arguments


Octane
05.01.2015, 03:05
Речь о том, чтобы никуда не передавать и не создавать ссылки на arguments, иначе выключаются оптимизации.

Пример:

function f1() {
f3(arguments);
}

function f2() {
var i = arguments.length;
var args = new Array(i);
while (i--) {
args[i] = arguments[i];
}
f3(args);
}

function f3(args) {
return args[0];
}

Как выяснилось по тестам http://jsperf.com/leaking-arguments/2 код с функцией f2 работает гораздо быстрее, не смотря на то, что выполняет лишние действия.

На mbp c core i5 2.4GHz:
- как не странно Chrome 41 показывается практически одинаковые результаты (хотя это как бы для V8 оптимизация https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments)
- Firefox 35 в 5 раз быстрее!
- Safari 8 в 4 раза быстрее
- IE11 в 2 раза быстрее

Что-то я раньше не придавал этому большого значения, думал что это только для V8 актуально, а он и так быстрый, но как оказалось следует так делать для всех браузеров.

Erolast
05.01.2015, 07:56
- как не странно Chrome 41 показывается практически одинаковые результаты (хотя это как бы для V8 оптимизация https://github.com/petkaantonov/blue...ging-arguments)
- Firefox 35 в 5 раз быстрее!
- Safari 8 в 4 раза быстрее
- IE11 в 2 раза быстрее
Win7, intel core i3-2100 3.1GHz, Firefox 36 - в 16 раз быстрее :)

nerv_
05.01.2015, 11:31
Octane, вторая функция разве не заменяется на это
Array.prototype.slice.call(arguments);
?

Octane
05.01.2015, 15:17
вторая функция разве не заменяется на это
Array.prototype.slice.call(arguments);?
Судя по руководству Optimization killers (https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments), безопасно передать arguments можно только в apply.

What is safe arguments usage?

Only use

• arguments.length
• arguments[i] where i is always a valid integer index into the arguments, and can not be out of bound
• Never use arguments directly without .length or [i] (STRICTLY x.apply(y, arguments) is ok, nothing else is, e.g. .slice. Function#apply is special)

And note that the FUD about mentioning arguments causing an allocation of the arguments object is untrue when you use the it in the mentioned safe ways.

ну и на тестах это подтверждается, вариант с slice.call самый медленный http://jsperf.com/leaking-arguments/3

krutoy
05.01.2015, 16:07
Octane,
То что ты пишешь, больше похоже на пляски с бубнами и заклинания. Толк от таких мизерных оптимизаций будет только один: ты запутаешь и усложнишь код, и твое приложение будет тормозить раз в сто сильней.

К тому же, ты сравниваешь теплое с мягким. Ты в одном случае передаешь в f3 объект, а в другом -- массив. Возможно твои "тормоза" по большей части связаны с извлечением по ключу из объекта. return args[0];

krutoy
05.01.2015, 16:20
Octane,

вот объективное сравнние, из которого видно, что сам объект аргументс тут не причем. И он даже выигрывает в V8, кстати.

UPD в FF -- тоже


function f1() {
f3(arguments);
}

function f2(args) {
f3(args);
}

function f3(args) {
return args[0];
}

i=100000
console.time("f1")
while(i--) f1(1,2,3)
console.timeEnd("f1")

i=100000
console.time("f2")
while(i--) f2({0: 1, 1: 2, 2: 3})
console.timeEnd("f2")

melky
05.01.2015, 16:31
Octane, хай. может быть поможет: ссылька (http://javascript.ru/forum/misc/39446-razmery-funkcijj.html)

было бы круто заиметь окружение тестирования V8 в своих тестах, чтобы писать типа:


var lib = require('my-lib');

MUST_OPTIMIZE_NEXT_CALL('Передача числа');
lib.atan(45);

MUST_OPTIMIZE_NEXT_CALL('Передача строки'); // функция деоптимизируется. тест кинет ошибку здесь с сообщением "Передача строки"
lib.atan('ЙОЙО');


я вроде помню, во внутренних тестах V8 есть такой ужас(MUST_OPTIMIZE...), но как получить к этому доступ - хз

ну а чтобы конкретно ответить на твой вопрос, нужно качать dev версию v8 на линуксах, вызывать js код из него и смотреть лог движка. сейчас уже нельзя с уверенностью ничего сказать, ибо за год в движках могло многое измениться


вот причины деооптимизаций (https://code.google.com/p/chromium/codesearch#chromium/src/v8/src/bailout-reason.h&sq=package:chromium). там есть:

V(kAssignmentToParameterFunctionUsesArgumentsObjec t, \
"Assignment to parameter, function uses arguments object")


а вот и место (https://code.google.com/p/chromium/codesearch#chromium/src/v8/src/hydrogen.cc&q=kAssignmentToParameterFunctionUsesArgumentsObjec t&sq=package:chromium&l=6638&type=cs), где она кидается (hydrogen - это оптимизирующий движок в V8, если память не изменяет)

switch (var->location()) {
case Variable::CONTEXT: {
// Bail out if we try to mutate a parameter value in a function
// using the arguments object. We do not (yet) correctly handle the
// arguments property of the function.
if (current_info()->scope()->arguments() != NULL) {
// Parameters will be allocated to context slots. We have no
// direct way to detect that the variable is a parameter so we do
// a linear search of the parameter variables.
int count = current_info()->scope()->num_parameters();
for (int i = 0; i < count; ++i) {
if (var == current_info()->scope()->parameter(i)) {
Bailout(kAssignmentToParameterFunctionUsesArgument sObject);
}
}
}


сама Variable::CONTEXT (https://code.google.com/p/chromium/codesearch#chromium/src/v8/src/variables.h&sq=package:chromium&l=47&type=cs)


// An indexed slot in a heap context. index() is the variable index in
// the context object on the heap, starting at 0. scope() is the
// corresponding scope.
CONTEXT,


и теперь стало ещё непонятней ...
мало того, что на вопрос не ответил, так и сам запутался :)

в общем, если кто завладеет D8 в V8, отпишите сюда о результатах пож)

Octane
05.01.2015, 16:48
запутаешь и усложнишь код
Что сложного в том чтобы взять за правило: "не передавать arguments и не создавать ссылок на arguments"?
Возможно твои "тормоза" по большей части связаны с извлечением по ключу из объекта. return args[0];Это понятно. После вопроса nerv_ я добавил следующий тест (http://jsperf.com/leaking-arguments/3), где есть 2 варианта с передачей массива.

Octane
05.01.2015, 17:07
melky, по-моему процетированный тобой код про это

(function (a) {
arguments[0] = 2;
alert(a);
}(1));

krutoy
05.01.2015, 17:23
не передавать arguments и не создавать ссылок на arguments
Я серьзено спрашиваю. Ты можешь сказать, каким образом в твоем коде тестируется передача arguments?
Вот мое видение твоего кода. Ты что-то куда-то передаешь, что абсолютно не важно, что и куда. А затем уже, в итоге, ты сравниваешь производительность доступа к ключу объекта с доступом по ключу массива. Причем тут arguments ты можешь четко сказать?

Если я напишу

[1][0] vs {0: 1}[0]

Это тоже будет проверка arguments?

Octane
05.01.2015, 17:42
Да знаю я, что значения массива быстрее достаются, чем свойства объекта. добавил следующий тест (http://jsperf.com/leaking-arguments/3), где есть 2 варианта с передачей массиваТам f2 и f3 передают массивы, но f2 быстрее.

nerv_
05.01.2015, 19:35
Как выяснилось по тестам http://jsperf.com/leaking-arguments/2 код с функцией f2 работает гораздо быстрее, не смотря на то, что выполняет лишние действия.
два раза запускал https://yadi.sk/i/83VILVundo9PP

Не совсем понятно, куда может потребоваться передавать ссылку на аргументы. Разве что, на данный момент, за неимением классов из es6.

Octane
05.01.2015, 19:41
Да в Chrome иногда даже немного медленее, поэтому и думал, что это хреновый совет в руководстве Optimization-killers (https://github.com/petkaantonov/bluebird/wiki/Optimization-killers), которое читал пол года или больше назад, а сейчас что-то дорвался проверить в других браузерах :)

nerv_
05.01.2015, 19:46
а в Chrome иногда даже немного медленее, поэтому и думал, что это хреновый совет в руководстве
На мой взгляд пытаться гнаться за оптимизациями подобного рода бесполезно. Достаточно придерживаться здравого смысла.
Что касается V8: сегодня он работает так, завтра по другому, послезавтра V9. :)