Компания
1 337,36
рейтинг
10 сентября 2014 в 13:51

Разработка → Анализ рендеринга через Skia Debugger: как можно найти самые дорогие для отрисовки элементы

Доброго дня, недавно я решал проблему притормаживания скролла на страницах Почты Mail.Ru. Особенно эта проблема была заметна на retina-дисплеях. После простого анализа я пришел к выводу, что одна из основных проблем — это медленная отрисовка страницы.

В этой статье я расскажу, как можно применять инструмент Skia Debugger, входящий в набор инструментов Chrome, для пошагового анализа процесса отрисовки страницы, а также как с его помощью можно получить данные о том, сколько времени занимает отрисовка каждого элемента.

Как и многие подобные проблемы оптимизации, данную проблему можно решить множеством способов. Я взялся за оптимизацию рендеринга, так как на нее затрачивалось значительное количество времени. Тем самым, я достаточно быстро смог бы получить прирост производительности и, соответственно, улучшить плавность скролла, ускорив отрисовку.



В начале я решил посмотреть, сколько времени занимает отрисовка страницы. Для этого можно использовать настройку devtools “Enable continuos page repainting”. Данная опция заставляет браузер постоянно перерисовывать страницу без каких-либо действий пользователя. В этом режиме также отображается панель со временем отрисовки страницы. Про эту и другие возможности devtools отлично рассказано в этой статье, так что я не буду заострять внимание на ней. Скажу лишь, что после снятия замеров оказалось, что анализируемая страница на ретине рендерится порядка 100 миллисекунд, что и создает притормаживания при скролле страницы. Данные, которые я могу посмотреть при записи timing’а в devtools, были не очень информативны, так как они содержали только время отрисовки страницы целиком, а мне нужно было найти виновника проблем.

Поэтому я стал искать, какой компонент браузера отвечает за отрисовку, и какие логи смогут помочь мне понять, что же тормозит. Начал я с изучения этой статьи и архитектуры Chromium, которая доступна в открытом доступе и концептуально не отличается от архитектуры Chrome.

В этих статьях меня интересовало, какой компонент отвечает за рендеринг и какие логи он предоставляет. Из глав с описанием графических компонентов я узнал, что в основном вся работа лежит на библиотеке Skia. К моей радости, для нее был разработан отладчик Skia Debugger, который, судя по скринам на сайте проекта, был мне необходим. Но, к сожалению, его установка была для меня нетривиальной задачей (нужно было собрать сам отладчик и пересобрать Chrome).

Поискав еще немного, я нашел ссылку на это видео. Из него я узнал, что данный отладчик был встроен в Chrome Canary, и его можно использовать, запустив браузер с параметром --enable-skia-benchmarking, в Mac это можно сделать следующей командой:
/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --enable-skia-benchmarking

Запустив браузер с этим параметром, переходим по адресу chrome://tracing. Вам должна отобразиться следующая вкладка:



Открываем еще одну вкладку со страницей, которую мы хотим проанализировать. В моем случае это была страница списка писем. Возвращаемся обратно к вкладке chrome://tracing и нажимаем Record, должен открыться попап. В нем нужно выбрать из списка пункт “Frame Viewer” и нажать на Record. После этого начнется запись, и вы можете выполнить какие-либо действия на анализируемой вкладке, рекомендую держать открытой не более одной вкладки, так как буфер записи очень ограничен, и в него влезает сравнительно небольшой кусок данных.

Как только вы выполнили интересующие вас действия, возвращаемся обратно к вкладке tracing и нажимаем Stop. После этого вам построится диаграмма, содержащая информацию о том, что происходило в системе при записи. Все данные сгруппированны по процессам браузера. Меня интересует процесс со списком сообщений, его легко найти по заголовку. В этом процессе смотрим раздел сс::Picture, в котором кружочками отображены итоговые отрисованные браузером изображения.



Найдем среди них одно, которое содержит отрисовку страницы целиком. Теперь в нижней части экрана отобразилось окно с картинкой страницы. В правом верхнем углу отображена диаграмма, в которой показано, сколько суммарного времени занимает каждая функция отрисовки. Слева отображена временная шкала с последовательностью отрисовки элементов страницы и затраченное на каждое из них время.



Пролистав временную шкалу, я нашел, что основной виновник столь долгой отрисовки страницы – контейнер списка сообщений с тенью. Данный элемент занимает порядка 45% всего времени отрисовки страницы.



После того как я заменил box-shadow на обычный border и заново записал страницу, я увидел, что количество времени на отрисовку уменьшилось c 45% до 6.5%, а также, что теперь используется уже другая функция Skia.



Ускорение отрисовки также подтвердилось после просмотра оптимизированной страницы в режиме “Enable continuos page repainting”.

Многим может показаться, что проблема с box-shadow была очевидна, и ее можно было бы найти, просто изменив стили на страницы через devtools. Но мне в этой статье хотелось рассказать о том, как можно применять альтернативные инструменты. Как с их помощью можно понять, в какой последовательности рисуются элементы на странице и сколько конкретно времени это занимает.

Данный инструмент обладает куда большими возможностями, которые я не описал в статье, так как про них прекрасно рассказано в видео, про которое я упоминал ранее.

Понимание процессов протекающих в браузере — очень важные знания, которые необходимы для эффективной оптимизации веб-приложений. Но для оптимизации также необходимы инструменты, которые позволят нам измерить ускорение, которое дала та или иная оптимизация, а также понять причину проблемы.

«Если речь идет о производительности, не может быть никаких «вероятно». Без измерения производительности вы никак не сможете точно узнать, помогли ваши изменения программе или навредили».
Стив Макконел «Совершенный код» 2-е. издание, стр. 579 «Стратегии оптимизации кода»

Определение наиболее тяжелых для отрисовки элементов — это важный шаг по оптимизации веб-приложения. Полученные знания по новым возможностям Chrome помогут не только отлаживать и находить узкие места отрисовки, но также понимать, как любой из компонентов страницы влияет на весь процесс рендеринга потока в целом. О других возможностях данного инструмента я постараюсь рассказать в следующих статьях.

Ссылки

Автор: @burlakilia

Комментарии (8)

  • +5
    Отличная статья! А может что нибудь посоветуете в плане JS? Ну, например, открываем страницу с большим количеством JS и как понять, что сколько времени выполняется. Для современных 2.0 сайтов актуально.
  • +3
    Спасибо.
    Для начала можно начать с анализа timing'a страницы и профилирования CPU через devtools. А потом можно посмотреть в chrome://tracing используя при записи пункт «Javascript and rendering».
  • 0
    i.imgur.com/4jpsfvE.png
    Почему-то именно в вашем блоге на хабре дикие лаги. Наблюдаю больше недели точно. Хотел пройтись по пунктам статьи, но выяснилось, что:
    1) проблемы только в первой открытой вкладке,
    2) когда первая закрывается, то начинает лагать вторая,
    3) ситуацию меняет магическим образом изменение размеров окна.

    После 3го пункта пока не могу воспроизвести ситуацию.
    • 0
      А надо ж расширения отключать перед тестом.
      • 0
        Как повторится, попробую более педантично подойти.
  • +22
    Спасибо за интересный обзор. В свою очередь хотел бы отметить следующее.

    В целом «притормаживание скролла» указывает на другую проблему, а именно композиция слоёв (layer compositing). Так как сегодня практически все браузеры используют GPU для отрисовки некоторых вещей, а отовсюду слышится «ставь translateZ(0) чтобы быстро и плавно всё» эта проблема становится очень актуальной.

    Если коротко, то в браузерах (как минимум на базе WebKit и Blink) есть набор триггеров, которые переносят некоторые слои на отдельную поверхность на GPU (в терминах Blink это перенос RenderLayer на свой GraphicsLayer). Эти триггеры могут быть как явно указаными у слоя (тот же translateZ(0), CSS-анимации на transform и opacity), так и косвенными, например, не-GPU слой по z-index’у находится выше GPU-слоя и их границы пересекаются.

    Вынос на GPU, помимо каких-то внутренних процессов, как правило сопровождается полной перерисовкой слоя, поэтому иногда можно наблюдать всякие «моргания» и прочие артефакты. На GPU такие слои фактически становятся текстурой на плоскости, которой удобно (а самое главное — очень дёшево) можно применять различные 3D-трансформации. Но тут есть один очень важный нюанс: если хотя бы один пиксель текстуры поменяется (например, на ховер, анимацию, что-то ещё) — её нужно заново перерисовать. Это очень сильно заметно, например, в WebKit на iOS. Соответственно, неумелое использование GPU-триггеров для «ускорения» страницы может на самом деле привести к очень серьёзным тормозам.

    Из всего вышесказанного конкретно для вашей ситуации: скорее всего, источник проблемы не в самом box-shadow, а в неправильной композиции, которая вызывает неявный вынос на GPU ненужных слоёв и, соответственно, перерисовку тени. Потому что при правильной композиции можно обвешаться различными эффектами и ничего не будет тормозить. Наверняка при включении “Show paint rectangles” вы наблюдали, что область перерисовки занимает всю станицу, хотя по-хорошему так быть не должно.

    Дебажить такие вещи очень удобно Safari Web Inspector: там есть отдельная панелька Layers, которая для выделенного элемента показывает, какие слои вынесены на GPU и, что особенно важно, причину такого выноса. Лично я уже нескольким ребятам помог сильно оптимизировать производительность с помощью этого инструмента, особенно для мобилок :)

    Чуть подробнее об этом можно почитать тут: www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome
    • 0
      Да я тоже думал смотреть в эту сторону, так как действительно в моем случае перерисовывается вся страница каждый раз при скроле. Спасибо за полезную информацию.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Самое читаемое Разработка