Инструмент «Профилирование рендеринга на графическом процессоре» показывает относительное время, которое каждый этап конвейера рендеринга затрачивает на рендеринг предыдущего кадра. Эти данные помогут выявить узкие места в конвейере, чтобы оптимизировать его и повысить производительность рендеринга вашего приложения.
На этой странице кратко объясняется, что происходит на каждом этапе конвейера, и обсуждаются проблемы, которые могут вызывать узкие места. Перед прочтением этой страницы вам следует ознакомиться с информацией, представленной в разделе «Профиль скорости рендеринга на GPU» . Кроме того, для понимания того, как все этапы взаимодействуют друг с другом, может быть полезно рассмотреть принцип работы конвейера рендеринга.
Визуальное представление
Инструмент Profile GPU Rendering отображает этапы и их относительное время в виде графика: цветовой гистограммы. На рисунке 1 показан пример такого отображения.

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

Как только вы поймете, что означает каждый цвет, вы сможете целенаправленно оптимизировать производительность отрисовки вашего приложения в определенных аспектах.
Этапы и их значения
В этом разделе объясняется, что происходит на каждом этапе, а также указываются причины возникновения проблем, на которые следует обратить внимание.
Обработка ввода
Этап обработки ввода в конвейере измеряет, сколько времени приложение потратило на обработку событий ввода. Этот показатель указывает, сколько времени приложение потратило на выполнение кода, вызываемого в результате обратных вызовов событий ввода.
Когда этот сегмент велик
Высокие значения в этой области обычно являются результатом слишком большого объема или слишком сложной работы, выполняемой внутри обработчиков событий ввода. Поскольку эти обработчики всегда выполняются в основном потоке, решения этой проблемы сосредоточены на оптимизации работы напрямую или на переносе работы в другой поток.
На этом этапе также может происходить прокрутка по LazyColumn или LazyRow . Как только касание пользователя квалифицируется как прокрутка, ленивый список обрабатывает события касания для динамического компоновки и размещения элементов. Если ваше приложение выполняет пользовательскую работу в ответ на изменения положения прокрутки , важно сделать эту операцию как можно быстрее, чтобы предотвратить выпадение кадров. Инструменты профилирования, такие как CPU Profiler в Android Studio или Perfetto, могут помочь вам в дальнейшем исследовании. Дополнительную информацию см. в разделе «Обзор трассировки системы» .
Анимации
На этапе анимации отображается время, затраченное на оценку всех состояний анимации, выполнявшихся в данном кадре. К распространенным API анимации в Compose относятся animate*AsState , Transition и Animatable . Кроме того, на этом этапе запускается Recomposer для обработки изменений состояния и обновления композиций. Это означает, что накладные расходы на перекомпозицию часто проявляются непосредственно на этапе анимации.
Для пользовательских интерфейсов Jetpack Compose подключите библиотеку Compose Runtime Tracing , чтобы просматривать подробные трассировки процесса создания композиции вместе с системными событиями.
Когда этот сегмент велик
Высокие значения в этой области обычно являются результатом работы, выполняемой из-за изменений состояния, вызванных анимацией. Например, анимация прокрутки, которая перемещает элемент LazyColumn или LazyRow , приводит к быстрому формированию, измерению и выделению новых элементов списка.
Мера
Для отрисовки элементов на экране Android выполняет три этапа обработки узлов компоновки в дереве пользовательского интерфейса.
Сначала система измеряет узлы компоновки. Каждый компонуемый объект имеет определенные ограничения и модификаторы, описывающие пределы размера объекта на экране. Некоторые компонуемые объекты могут иметь определенный фиксированный размер; другие имеют размер, который адаптируется к ограничениям, передаваемым родительским контейнером компоновки.
Во-вторых, система размещает узлы компоновки. После того как Compose вычислит размеры дочерних узлов на этапе измерения, она может перейти к этапу размещения, на котором она определяет размеры и положение узлов компоновки на экране.
Система всегда выполняет эту однопроходную компоновку для повышения эффективности. Когда компонуемая компоновка становится недействительной, Compose измеряет состояние этого конкретного узла и распространяет обновления компоновки на родительские иерархии только в том случае, если дочерний узел изменяет свой размер или ограничения.
Когда этот сегмент велик
Большой сегмент в этой области означает, что приложение тратит слишком много времени на фазу компоновки , которая состоит из позиционирования и определения размера узлов компоновки. Эти операции включают выполнение модификаторов измерения и размещения для компонуемых элементов, что может задерживать подготовку фрейма, если дерево компоновки слишком сложное. В таких случаях решение проблемы производительности включает в себя тестирование производительности вашего приложения Compose и следование лучшим практикам повышения производительности .
Используйте CPU Profiler в Android Studio или Perfetto для анализа проходов компоновки и выявления узких мест. Дополнительную информацию см. в разделе «Обзор трассировки системы» .
Рисовать
На этапе отрисовки операции рендеринга, такие как рисование фона, фигуры или текста, преобразуются в последовательность собственных команд отрисовки. Система захватывает эти команды в список для отображения и выполнения на графическом процессоре.
Полоса отрисовки показывает, сколько времени требуется для завершения захвата команд в список отображения для всех узлов компоновки, которые необходимо было обновить на экране для этого кадра. Измеренное время также применяется к любой пользовательской логике отрисовки, которая может быть использована внутри модификаторов отрисовки или в составном холсте.
Когда этот сегмент велик
Проще говоря, этот показатель отражает время, затраченное на выполнение всех команд отрисовки для каждого недействительного узла компоновки. В это время входит также время, затраченное на отправку этих команд дочерним узлам и векторным объектам отрисовки. Поэтому, если вы видите этот пик на графике, причиной может быть внезапное недействительность многих элементов компоновки. Недействительность требует повторного выполнения команд отрисовки и перегенерации списков отображения узлов компоновки. В качестве альтернативы, длительное время может быть результатом наличия у некоторых пользовательских элементов компоновки или холстов чрезвычайно сложной логики в их реализации DrawScope .
Кроме того, Compose часто обрабатывает внутренние проходы измерения и компоновки в рамках того, что платформа считает этапом отрисовки. Следовательно, повышенная планка отрисовки может быть вызвана дорогостоящими или избыточными внутренними операциями измерения/компоновки, а не только командами отрисовки. В случае сомнений, запишите трассировку Perfetto, чтобы определить, связана ли избыточность с процедурами отрисовки или с проходами измерения и компоновки Compose.
Загрузить
Показатель загрузки отражает время, необходимое для передачи растровых объектов из памяти ЦП в память ГП в течение текущего кадра.
Поскольку это разные процессоры, ЦП и ГП имеют разные области оперативной памяти, выделенные для обработки. Когда вы рисуете растровое изображение на Android, система передает его в память ГП, прежде чем ГП сможет отобразить его на экране. Затем ГП кэширует растровое изображение, чтобы системе не нужно было снова передавать данные, если только текстура не будет вытеснена из кэша текстур ГП.
Примечание: на устройствах с Android Lollipop этот этап имеет фиолетовый цвет.
Когда этот сегмент велик
Все ресурсы для кадра должны находиться в памяти графического процессора, прежде чем их можно будет использовать для отрисовки кадра. Это означает, что высокое значение этого показателя может указывать либо на большое количество небольших загрузок ресурсов, либо на небольшое количество очень больших загрузок ресурсов. Типичный случай — когда приложение отображает одно растровое изображение, размер которого близок к размеру экрана. Другой случай — когда приложение отображает большое количество миниатюр.
Чтобы уменьшить эту полосу, можно использовать такие методы, как:
- Убедитесь, что разрешение ваших растровых изображений не намного превышает размер, в котором они будут отображаться. Например, избегайте отображения изображения размером 1024x1024 пикселей как изображения размером 48x48 пикселей.
- Использование современных библиотек, таких как Coil, позволяет асинхронно предварительно загрузить растровое изображение перед следующей фазой синхронизации.
Выдавайте команды
Сегмент «Выдача команд» отображает время, необходимое для выполнения всех команд, необходимых для вывода списков на экран.
Для отрисовки списков элементов на экране система отправляет необходимые команды графическому процессору. Как правило, это делается с помощью API OpenGL ES .
Этот процесс занимает некоторое время, поскольку система выполняет окончательное преобразование и обрезку для каждой команды, прежде чем отправить команду на графический процессор. Затем на стороне графического процессора возникают дополнительные накладные расходы, связанные с вычислением окончательных команд. Эти команды включают в себя окончательные преобразования и дополнительную обрезку.
Когда этот сегмент велик
Время, затраченное на этом этапе, является прямым показателем сложности и количества списков отображения, которые система отрисовывает в данном кадре. Например, большое количество операций отрисовки, особенно в случаях, когда каждая операция отрисовки сопряжена с небольшими затратами, может значительно увеличить это время. Например:
for (i in 0 until 1000) { canvas.drawPoint() }
Выпуск обходится гораздо дороже, чем:
canvas.drawPoints(thousandPointArray)
Не всегда существует прямая корреляция между отправкой команд и фактической отрисовкой списков отображения. В отличие от полосы отправки команд, которая отражает время, необходимое для отправки команд отрисовки на графический процессор, метрика отрисовки представляет собой время, необходимое для захвата отправленных команд в список отображения.
Это различие возникает из-за того, что списки отображаемых элементов кэшируются системой везде, где это возможно. В результате возникают ситуации, когда прокрутка, преобразование или анимация требуют от системы повторной отправки списка отображаемых элементов, но при этом нет необходимости фактически перестраивать его — повторно получать команды отрисовки — с нуля. В результате вы можете видеть полосу с большим количеством команд, не видя при этом полосу с большим количеством команд отрисовки.
Буферы обмена
После того как Android завершит отправку списка отображаемых изображений на графический процессор, система отправляет последнюю команду, чтобы сообщить графическому драйверу о завершении обработки текущего кадра. На этом этапе драйвер наконец может отобразить обновленное изображение на экране.
Когда этот сегмент велик
Важно понимать, что графический процессор (GPU) выполняет работу параллельно с центральным процессором (CPU). Система Android отправляет команды отрисовки графическому процессору, а затем переходит к следующей задаче. Графический процессор считывает эти команды отрисовки из очереди и обрабатывает их.
В ситуациях, когда ЦП отправляет команды быстрее, чем ГП их обрабатывает, очередь обмена данными между процессорами может переполниться. В этом случае ЦП блокируется и ждет, пока в очереди не освободится место для размещения следующей команды. Такое состояние переполнения очереди часто возникает на этапе обмена буферами, поскольку к этому моменту уже отправлено команд, достаточных для обработки целого кадра.
Ключ к решению этой проблемы заключается в снижении сложности работы, выполняемой на графическом процессоре, аналогично тому, как это делается на этапе выдачи команд.
Разнообразный
Помимо времени, необходимого системе рендеринга для выполнения своей работы, существует дополнительный набор задач, выполняемых в основном потоке и не имеющих отношения к рендерингу. Время, затрачиваемое на эту работу, указывается как «прочее время». Прочее время обычно представляет собой работу, которая может выполняться в потоке пользовательского интерфейса между двумя последовательными кадрами рендеринга.
Когда этот сегмент велик
Если это значение высокое, вероятно, ваше приложение содержит обратные вызовы, интенты или другую работу, которая должна выполняться в другом потоке. Такие инструменты, как CPU Profiler в Android Studio или Perfetto, могут предоставить информацию о задачах, выполняющихся в основном потоке. Эта информация поможет вам определить приоритетные направления для повышения производительности. Дополнительную информацию см. в разделе «Обзор трассировки системы» .