company_banner

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

    Ссылки

    • +68
    • 18,3k
    • 8
    Mail.Ru Group 795,14
    Строим Интернет
    Поделиться публикацией
    Похожие публикации
    Комментарии 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
            Да я тоже думал смотреть в эту сторону, так как действительно в моем случае перерисовывается вся страница каждый раз при скроле. Спасибо за полезную информацию.

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

          Самое читаемое