Тестирование скорости выполнения JS или отображения страниц — занятие неблагодарное. Любое тестирование отражает действительность только тогда, когда оно выполнено в как можно более одинаковых условиях и тестируются идентичные по функциональности вещи. Ведь на вопрос, что быстрее, грузовик или спорткар, каждый тут же ответит, что спорткар. А если по полю да с прицепом навоза? Победитель в каждом случае будет тот, кто лучше всего приспособлен для выполнения специфических задач.
В этой статье будет немного гипотез и немного фактов. Не будет фанатских речей и призывов сменить браузерную ориентацию.
Итак, наши подопытные кролики:
Я не тестировал IE9, потому что у меня он установлен на виртуальной машине, а это чревато наличием пенальти по скорости и ощутимым разбросом значений.
Гонка за скоростью работы JS-движка сделала благое дело: увеличила отзывчивость браузеров, дала кодерам больше возможностей по управлению отображением страниц и сделал анимацию приятной для глаза. Это не все плюсы, и перечислять их можно долго. Узнали мы про чудеса оптимизации по замечательным бенчмаркам, таким как SunSpider, Dromaeo, V8 Benchmark Suite и другим. Теперь возникает вопрос, а что же намеряли все эти бенчмарки? Скорость выполнения JS? Возможно. А возможно и нет.
Давайте возьмем простой, коневакуумосферический пример: некий скрипт в цикле создает DOM-ноды, которые потом добавляет в документ.
Забегу немного вперед. Зная, что Javascript-движки могут существовать отдельно от браузера, я предполагаю, что выполнение нашего тестового скрипта будет разбито на три этапа:
Очевидно, что самым простым способом реализации механизма отображения элементов будет последовательное выполнение команд: сначала выполняем JS-функцию, по команде которой получим экземпляр DOM-ноды, которую отправим на рендеринг.
Это не самый плохой способ реализации. Главный его недостаток в том, что нельзя «отрезать» JS-движок от других функциональных частей браузера. Однако есть простой способ это обойти.
А давайте сделаем финт ушами и разделим наши слои некими очередями выполнения. Движок JS просто занесет в очередь набор команд для выполнения и пойдет себе спать, предварительно передав задачу дальше — фабрике DOM-объектов. Фабрика выполнит все нужные команды, попутно создав готовый для рендеринга набор объектов. Заносим все в очередь отрисовки и передаем эстафету системе рендеринга. Вуаля!
В такой архитектуре достаточно просто «отрезать» одну часть браузера от другой, общение-то происходит через очередь заданий.
В предыдущем варианте выполнение этапов идет последовательно. А что если сделать три параллельных системы? Фабрика DOM-объектов следит за очередью заданий, и как только появляется команда, сразу делает DOM-ноду и отправляет в очередь на отрисовку.
Страшно? Да, страшно интересно!
Давайте теперь измерим скорость выполнения JS каждой из представленных выше архитектур. Еще не начиная тестирование, уже понятно, что в первом случае мы измерим скорость выполнения всех трех этапов, во втором и третьем — только скорость создания очередей. Но это же не будет отражать действительность!
Чтобы уравнять три подхода, я сделал простой бенчмарк (RapidShare / Yandex / pasteBin). Случайным образом генерируются клоны нескольких заготовок. Если клон последний в строке, то ему присваивается ширина таким образом, чтобы он занимал все доступное свободное пространство. Элементы плавающие и пока не будут отрисованы, не понятно какая позиция и ширина у них. Фактически, я максимально привел все к последовательному исполнению команд.
Тестирование меня реально удивило.
Для начала посмотрим на результаты тестирования без нагрузки.
Фокс в три раза отстает от Оперы и Хрома. Хром чуть быстрее Оперы, но с ростом количества итераций отставание сокращается.
А теперь включаем «тормоз»
Я не поверил своим глазам. На тысяче итераций Хром впадает в жестокую задумчивость и выдает просьбу не издеваться над его ранимой душой и прекратить страдания путем остановки выполнения скрипта. Вот это палка в колеса!
Опера безоговорочно выиграла соревнования, Фокс второй.
Если взять отношение результатов с нагрузкой к результатам без оной, то мы видим достаточно интересную картину. Firefox теряет в производительности от 50 до 100 раз. Деградация скорости от количества итераций почти линейная. Картина и поведение браузера очень хорошо ложится в первую схему — последовательное исполнение шагов. Визуально, Фокс не отрисовывает страницу, пока не закончит цикл.
У Оперы деградация скорости при включении нагрузки составляет от 100 до 150 раз. Опера отрисовывает страницу по мере выполнения скрипта, что очень похоже на схему параллельного выполнения трех этапов.
Деградация скорости у Хрома составляет от 1000 до 4000 раз. Хром не отрисовывает страницу, пока не закончит выполнение цикла. Это очень похоже на схему поочередного выполнения этапов.
Забавно выходит.
Моя статья носит частично теоретический характер и архитектуры, которые представлены в ней, не подтверждены фактически.
При создании скриптов, которые анализируют размеры элементов, будьте аккуратны и бдительны. Различия в архитектуре рендеринга может привести к плачевной деградации скорости.
UPD. Добавил ссылку на бенчмарк на Yandex.
Многие спрашивают, в какой программе я создаю диаграммы. В Corel Photopaint X5 вручную.
UPD2. Добавил ссылку на pasteBin. Спасибо, друзья!.
В этой статье будет немного гипотез и немного фактов. Не будет фанатских речей и призывов сменить браузерную ориентацию.
Итак, наши подопытные кролики:
- FF 4b7
- Opera 10.63
- Chrome 7
Я не тестировал IE9, потому что у меня он установлен на виртуальной машине, а это чревато наличием пенальти по скорости и ощутимым разбросом значений.
JS-движки оптимизировали, оптимизировали, да не выоптимизировали
Гонка за скоростью работы JS-движка сделала благое дело: увеличила отзывчивость браузеров, дала кодерам больше возможностей по управлению отображением страниц и сделал анимацию приятной для глаза. Это не все плюсы, и перечислять их можно долго. Узнали мы про чудеса оптимизации по замечательным бенчмаркам, таким как SunSpider, Dromaeo, V8 Benchmark Suite и другим. Теперь возникает вопрос, а что же намеряли все эти бенчмарки? Скорость выполнения JS? Возможно. А возможно и нет.
Что нам стоит DOM построить?
Давайте возьмем простой, коневакуумосферический пример: некий скрипт в цикле создает DOM-ноды, которые потом добавляет в документ.
Забегу немного вперед. Зная, что Javascript-движки могут существовать отдельно от браузера, я предполагаю, что выполнение нашего тестового скрипта будет разбито на три этапа:
- Выполнение JS-функции создания ноды (для упрощения назовем это «JS»)
- Создание DOM-объекта в браузере (DOM)
- Отрисовка ноды (Rendering)
Последовательное выполнение
Очевидно, что самым простым способом реализации механизма отображения элементов будет последовательное выполнение команд: сначала выполняем JS-функцию, по команде которой получим экземпляр DOM-ноды, которую отправим на рендеринг.
Это не самый плохой способ реализации. Главный его недостаток в том, что нельзя «отрезать» JS-движок от других функциональных частей браузера. Однако есть простой способ это обойти.
Поочередное выполнение задач
А давайте сделаем финт ушами и разделим наши слои некими очередями выполнения. Движок JS просто занесет в очередь набор команд для выполнения и пойдет себе спать, предварительно передав задачу дальше — фабрике DOM-объектов. Фабрика выполнит все нужные команды, попутно создав готовый для рендеринга набор объектов. Заносим все в очередь отрисовки и передаем эстафету системе рендеринга. Вуаля!
В такой архитектуре достаточно просто «отрезать» одну часть браузера от другой, общение-то происходит через очередь заданий.
Полный параллелелизм
В предыдущем варианте выполнение этапов идет последовательно. А что если сделать три параллельных системы? Фабрика DOM-объектов следит за очередью заданий, и как только появляется команда, сразу делает DOM-ноду и отправляет в очередь на отрисовку.
Страшно? Да, страшно интересно!
Тестирование
Давайте теперь измерим скорость выполнения JS каждой из представленных выше архитектур. Еще не начиная тестирование, уже понятно, что в первом случае мы измерим скорость выполнения всех трех этапов, во втором и третьем — только скорость создания очередей. Но это же не будет отражать действительность!
Чтобы уравнять три подхода, я сделал простой бенчмарк (RapidShare / Yandex / pasteBin). Случайным образом генерируются клоны нескольких заготовок. Если клон последний в строке, то ему присваивается ширина таким образом, чтобы он занимал все доступное свободное пространство. Элементы плавающие и пока не будут отрисованы, не понятно какая позиция и ширина у них. Фактически, я максимально привел все к последовательному исполнению команд.
Тестирование меня реально удивило.
Для начала посмотрим на результаты тестирования без нагрузки.
500 | 750 | 1000 | |
---|---|---|---|
Firefox | 19 | 30 | 45 |
Opera | 6 | 10 | 14 |
Chrome | 5 | 9 | 14 |
Фокс в три раза отстает от Оперы и Хрома. Хром чуть быстрее Оперы, но с ростом количества итераций отставание сокращается.
А теперь включаем «тормоз»
500 | 750 | 1000 | |
---|---|---|---|
Firefox | 950 | 2350 | 4800 |
Opera | 610 | 1250 | 2100 |
Chrome | 5700 | 20500 | ~55000 |
Я не поверил своим глазам. На тысяче итераций Хром впадает в жестокую задумчивость и выдает просьбу не издеваться над его ранимой душой и прекратить страдания путем остановки выполнения скрипта. Вот это палка в колеса!
Опера безоговорочно выиграла соревнования, Фокс второй.
Немного анализа
Если взять отношение результатов с нагрузкой к результатам без оной, то мы видим достаточно интересную картину. Firefox теряет в производительности от 50 до 100 раз. Деградация скорости от количества итераций почти линейная. Картина и поведение браузера очень хорошо ложится в первую схему — последовательное исполнение шагов. Визуально, Фокс не отрисовывает страницу, пока не закончит цикл.
У Оперы деградация скорости при включении нагрузки составляет от 100 до 150 раз. Опера отрисовывает страницу по мере выполнения скрипта, что очень похоже на схему параллельного выполнения трех этапов.
Деградация скорости у Хрома составляет от 1000 до 4000 раз. Хром не отрисовывает страницу, пока не закончит выполнение цикла. Это очень похоже на схему поочередного выполнения этапов.
Забавно выходит.
Заключение
Моя статья носит частично теоретический характер и архитектуры, которые представлены в ней, не подтверждены фактически.
При создании скриптов, которые анализируют размеры элементов, будьте аккуратны и бдительны. Различия в архитектуре рендеринга может привести к плачевной деградации скорости.
UPD. Добавил ссылку на бенчмарк на Yandex.
Многие спрашивают, в какой программе я создаю диаграммы. В Corel Photopaint X5 вручную.
UPD2. Добавил ссылку на pasteBin. Спасибо, друзья!.