V8 нахождение деоптимизаций
Чтобы понимать, о чём суть, можно ознакомиться с этой статьёй.
Презентация об оптимизации компилирования JavaScript в V8 Думаю, все знают о том, как управлять качеством компилируемого JavaScript - наверняка это относится не только к V8, но и к FireFox'овским компилятором, которые он меняет через неск. версий (сейчас я про JIT компиляторы). Вкратце, всё сводится к тому, чтобы как можно более статично писать код - т.е. не использовать разные типы для одной переменной, не добавлять новые свойства к объекту и т.д. ... короче, чтобы получить действительно быстрый JavaScript, нужно как-то особенно писать. Тут то и возникает проблема. Вот вроде бы ты и написал, как "надо". Как теперь проверить, деоптимизируется ли функция? Вариант с бенчмарками отпадает, как самый примитивный. Я немного пощупал V8 (точнее, Chrome, ну да ладно) на предмет логирования его действий при обработке моего скрипта. Всё свелось к простейшему созданию особого ярлыка для Chrome, и перетаскиванию HTML-файла со скриптом на этот ярлык (я пока на виндовсе :)) : Код:
C:\Users\LOL\AppData\Local\Google\Chrome\Application\chrome.exe --no-sandbox Profiling Chromium With V8 Profiling Chromium With V8 №2 после этого в папке с chrome.dll появился файл лога, содержащий какие-то записи сумашедшего летописца. Вроде я указал, что мне нужно записывать , но поиск по файлу ничего путёвого, кроме какого-то левого профилирования, не выдал. Лог сам весит 211 кб :) Первое упоминание о моём файле аж на 656'й строке. Код:
code-creation,Function,0x369363a0,7992," file:///E:/Max/melanim/dist/mel-anim.compiled.js:5",0x26828704,~ ещё немного бреда : Код:
code-creation,LoadIC,0x3693d660,98,"prefix" особенно интересны эти моменты : Код:
code-creation,LazyCompile,0x36955160,232,"type.array file:///E:/Max/melanim/dist/mel-anim.compiled.js:73",0x268269a4,~ Короче, куча вопросов, и ответов нет. Попытки гугления при водят только к непонятной документации. Я хотел найти deopt'ы. Где они ?) Кто-нибудь вообще занимался этим? |
:( Пока нашел только это http://qps.ru/y5SKO
|
Излишняя оптимизация зло, которое может превратить код в какашку:)
|
Цитата:
Цитата:
Кстати, код для оптимизаций меняется не так сильно и совсем не уродуется : Parser.prototype.parse = function (s) { var length = '', i = 0; while (i < s.length) { if (s[i] == '\u0000') { length = Number(length); this.emit('data', s.substr(i + 1, length)); - s = s.substr(i + 1 + x); - i = 0; + i += length + 1; length = ''; } else { length += s[i++]; } } }; (я думаю, понятно, что за плюсы и минусы слева:) пример из презентации) Самое главное - обьяснить компилятору, что тут именно тот привычный типизированный быстрый код какого-нибудь C++, написанный на JavaScript; Всё, что я хочу - прочитать эти сказки о типизации, рассказанные компилятором в отношении моего кода. |
melky, если оптимизация реально нужна, то конечно нужно её делать, я лишь хотел сказать, что прочитав статью не нужно всем дружно бросаться переписывать наш код под каждый интерпретатор и фапать на мистический наносекунды:)
Цитата:
Collection.extend = function (deep, target, var_args) { deep = deep || false; target = target || {}; var aLength = arguments.length, aEl, key, src, copy, copyIsArray, i = 1, j, stack = [], level, last, lastEl; // Внешний цикл по расширяющим аргументам while (++i < aLength) { if ((aEl = arguments[i])) { // Цикл для эмуляции рекурсии while (aEl) { level = []; // Цикл по свойствам объекта for (key in aEl) { src = target[key]; copy = aEl[key]; // Защита от бесконечного копирования if (target === copy) { continue; } // Рекурсивное копирование свойств // (рекурсия развёрнута) if ( deep && copy && ((copyIsArray = Array.isArray(copy)) || typeof copy === 'object') ) { // Если копируемое свойство - массив if (copyIsArray) { copyIsArray = false; clone = src && Array.isArray(src) ? src : []; // Если копируемое свойство - объект } else { clone = src && typeof src === 'object' ? src : {}; } // Запоминаем вложенность, чтобы в дальнейшем к ней вернуться level.push({ target: target, clone: clone, aEl: aEl, copy: copy, key: key }); } else { target[key] = copy; } } // Если на уровне имеются вложенности, // то добавляем новый уровень в стек и // проиводим сдвиг в крайне правый элемент нового уровня if ((last = level.length)) { stack.push(level); last = level[last - 1]; // Ставим флаг, что элемент учавствует в обходе last['__COLLECTION_TMP__'] = true; // Устанавливаем новую точку отсчёта target = last.clone; aEl = last.copy; // На уровне нет вложенностей } else if ((last = stack.length)) { j = stack.length; while (j--) { lastEl = stack[j][stack[j].length - 1]; // Если звено не имеет детей и уже было использовано, // то удаляем крайне правый элемент и сдвигаем позицию обхода if (lastEl['__COLLECTION_TMP__'] && !stack[j + 1]) { lastEl.target[lastEl.key] = target; target = lastEl.target; aEl = lastEl.aEl; stack[j].pop(); // В звене не осталось элементов, // значит его можно удалить if (!stack[j].length) { stack.pop(); } // Если первое условие не верно, // значит продолжать цикл нет смысла } else { break; } } // Устанавливаем новую позицию обхода if ((last = stack.length)) { last = stack[last - 1]; lastEl = last[last.length - 1]; lastEl['__COLLECTION_TMP__'] = true; target = lastEl.clone; aEl = lastEl.copy; } } // Операция закончена if (!stack.length && !level.length) { break; } } } } return target; }; |
Цитата:
Имхо следует в dev-версии оставлять самый понятный код - т.е. рекурсию. Есть скрипты для разворачивания рекурсии в цикл ... я видел его, если мне не показалось, могу поискать, любопытная вещица. |
Цитата:
Цитата:
|
Цитата:
Тем, кто не в курсе про jit будет гораздо более понятно, нежели текстовый срез из доклада. Ну и линк на слайды: http://s3.mrale.ph/TechForum2012.pdf |
Цитата:
|
Gozar,
спасибо |
Часовой пояс GMT +3, время: 04:51. |