FrameHUD

Как читать панель

English · Русский

Формат строк: now avg peak (мс) — текущий кадр, среднее по окну (по умолчанию 120 кадров), пик с последнего reset. other и pipe собраны из других строк, поэтому заканчиваются на avg: собственного пика у них нет.

Бюджет кадра: FrameMetrics.DEADLINE (API 31+, столько система выделила кадру) или 1000 / refreshRate. На 60 Гц это 16.7 мс. Бюджет из frameBudgetsMs встаёт на его место. Тот бюджет, что действует сейчас, показан в заголовке.

На статичном экране показатели замирают. Кадров нет, отчитываться не о чем.

Управление

Панель перетаскивается пальцем. Тап переключает три вида ниже, long-press — freeze: показания замирают для чтения, сбор продолжается.

Вид Что показывает
Полный Все строки этой страницы, вплоть до сессии, памяти, температуры и ваших счётчиков
Кадр Вердикт, фазы, которыми управляет приложение, TOTAL и сводку окна
Одна строка Спарклайн, FPS, jank и фазу-виновника

Вид кадра не показывает стадии render и GPU, over и pipe. Приложение ими напрямую не управляет, а если проблема именно там — об этом говорит вердикт первой строкой.

В шапке три кнопки. ⧉ запрашивает разрешение на оверлей и видна, только пока панель заперта в окне приложения. ▤ переключает между показаниями и худшими экранами. × — reset окна, сессии и пиков.

Шапка

CPU (main thread)

Работа UI-потока, где живёт весь Compose и View-код приложения.

Строка Что покрывает Растёт когда
input Обработка тач-событий и клавиш, включая все onClick/onTouch коллбэки В обработчиках тяжёлая логика
anim Расчёт текущих значений анимаций (Animatable, animate*AsState, Transition) Много одновременных анимаций
layout Measure + layout всех View и Composable Глубокая иерархия, частые рекомпозиции, intrinsic measurements
draw Запись draw-команд в DisplayList (Canvas.draw*, текст, фоны) Много элементов на экране

RENDER (render thread)

Отдельный поток Android, который берёт DisplayList от UI-потока и превращает в GPU-инструкции.

Строка Что покрывает Растёт когда
sync Синхронизация DisplayList из UI-потока + загрузка bitmap’ов как GPU-текстур Большие или новые картинки
command Преобразование draw-команд в OpenGL/Vulkan вызовы и отправка на GPU Сложная иерархия View, много слоёв
swap Ожидание пока GPU закончит предыдущий кадр + вывод на экран (eglSwapBuffers) GPU перегружен

GPU

gpu — сколько GPU тратит на растеризацию кадра: шейдеры, отрисовка текстур, блендинг слоёв. Нужен Android 12+ (API 31) и драйвер, который эти тайминги отдаёт. Пока реальных значений нет, в строке n/a: часть драйверов их так и не присылает.

Прочее

Подвал

Метки

Пока открыто взаимодействие, в шапке вместо таймингов стоит ▸ имя. Это подпись к происходящему, а не рамка для цифр: строки ниже остаются на обычном окне и сессии, и только событие MarkEnded отчитывается по одной метке. Метку выставляет FrameHud.mark в приложении; сама панель их не ставит.

Вердикт

Строка под заголовком:

Цвета

Строки метрик: зелёный — TOTAL в бюджете, серый — норма, красный — среднее по окну выше бюджета.

FPS (цель — герцовка дисплея): зелёный — ≥ 95% от цели, серый — ≥ 75%, красный — ниже.

Jank: < 5% норм, 5–20% подлагивает, ≥ 20% лагает.

Как смотреть

Current прыгает, это нормально. Смотреть надо на average.

  1. FPS против герцовки: совпадают = плавно
  2. TOTAL average: ниже бюджета = хорошо
  3. jank: доля кадров, не уложившихся в дедлайн
  4. p95: устойчивые просадки
  5. max: разовые пики. Большой max при нормальном p95 = единичный хик, не проблема
  6. pipe: какая стадия ограничивает fps под нагрузкой

Как замерять экран

  1. Открыть нужный экран
  2. Reset (×)
  3. Погонять 5–10 сек: скролл, переходы, анимации
  4. Смотреть FPS против герцовки, TOTAL average, jank, p95
  5. Если плохо — вердикт и pipe подскажут виновника

Если что-то красное

Строка Что делать
input Тяжёлая логика в обработчиках тачей/кликов. Вынести работу из onClick/onTouch
anim Много или сложные анимации одновременно. Упростить, убрать лишние
layout Рекомпозиции. remember, derivedStateOf, меньше инвалидаций
draw Много элементов на экране. LazyColumn, убрать лишнее
sync Тяжёлые картинки. Размеры bitmap, resize в загрузчике изображений
command Слишком много draw-команд для render thread. Много слоёв, сложная иерархия
swap GPU не освободился вовремя для вывода кадра. Обычно следствие тяжёлого gpu
gpu GPU перегружен. Overdraw, blur, тени, alpha-слои, большие текстуры
delay Main thread заблокирован. IO/network не на том потоке
max > 100 мс при нормальном p95 Разовый хик, забить
frz > 0 UI замерзал заметно для глаза. Искать длинную работу на main thread
gc растёт вместе с jank Аллокации в горячем пути (композиция, скролл). Профилировать allocations
mem у лимита Близко к OOM, искать утечку или тяжёлые кэши

Насколько числам можно верить

Панель рисуется в отдельном окне и в метрики измеряемого окна не попадает.

Показания искажают три вещи, и все три панель показывает сама. drop больше нуля означает, что система выбросила отчёты, не успев доставить: avg и перцентили недосэмплированы. therm со статусом троттлинга означает, что устройство сбросило частоты, и тайминги несравнимы с холодным замером. EMU в шапке означает эмулятор. В отчётах эти и другие сигналы лежат рядом со статистикой как проблемы достоверности, каждая называет цифры, которые она портит.

На эмуляторе

Эмулятор рисует через хост-машину, поэтому sync, command, swap и gpu измеряют десктопную видеокарту и о телефоне не говорят ничего. Заголовки секций читаются как RENDER · host и GPU · host, сами строки погашены, и вердикт их не называет. pipe их называет, когда узкое место приходится на них, но тоже погашенным.

Панель на эмуляторе: бейдж EMU и погашенные строки хоста

Осмысленным остаётся всё, за что отвечает само приложение: input, anim, layout, draw, delay, TOTAL, jank и итоги сессии. Именно эти числа читает jank-гейт, поэтому гонять его на CI имеет смысл, хотя рендеринг там и не устройства.

Заодно вырастает other: на эмуляторе больше времени кадра не попадает ни в одну фазу, которую сообщает платформа, поэтому вердикт нередко указывает на этот остаток, а не на стадию.