Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   fix leaking arguments (https://javascript.ru/forum/misc/52752-fix-leaking-arguments.html)

Octane 05.01.2015 03:05

fix leaking arguments
 
Речь о том, чтобы никуда не передавать и не создавать ссылки на 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/blue...ging-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

Цитата:

Сообщение от nerv_
вторая функция разве не заменяется на это
Array.prototype.slice.call(arguments);
?

Судя по руководству Optimization killers, безопасно передать 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, хай. может быть поможет: ссылька

было бы круто заиметь окружение тестирования 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 код из него и смотреть лог движка. сейчас уже нельзя с уверенностью ничего сказать, ибо за год в движках могло многое измениться


вот причины деооптимизаций. там есть:
Код:

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

а вот и место, где она кидается (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(kAssignmentToParameterFunctionUsesArgumentsObject);
            }
          }
        }

сама Variable::CONTEXT

Код:

    // 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

Цитата:

Сообщение от krutoy
запутаешь и усложнишь код

Что сложного в том чтобы взять за правило: "не передавать arguments и не создавать ссылок на arguments"?
Цитата:

Сообщение от krutoy
Возможно твои "тормоза" по большей части связаны с извлечением по ключу из объекта. return args[0];

Это понятно. После вопроса nerv_ я добавил следующий тест, где есть 2 варианта с передачей массива.

Octane 05.01.2015 17:07

melky, по-моему процетированный тобой код про это
(function (a) {
    arguments[0] = 2;
    alert(a);
}(1));

krutoy 05.01.2015 17:23

Цитата:

Сообщение от Octane
не передавать arguments и не создавать ссылок на arguments

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

Если я напишу

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


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


Часовой пояс GMT +3, время: 01:52.