Сбор показателей Macrobenchmark

Показатели – это основной тип информации, извлекаемой из контрольных показателей. Они передаются функции measureRepeated в виде объекта List, что позволяет указать сразу несколько показателей. Для сравнения необходим хотя бы один тип показателей.

В следующем фрагменте кода показано, как получить показатели времени формирования кадра и пользовательского раздела трассировки для интерфейса ленивого макета Jetpack Compose:

@OptIn(ExperimentalMetricApi::class)
    @Test
    fun scrollComposeList() {
        benchmarkRule.measureRepeated(
            // [START_EXCLUDE]
            packageName = TARGET_PACKAGE,
            metrics = listOf(
                FrameTimingMetric(),
                // Measure power usage. This is supported on Pixel 6 and later.
                PowerMetric(PowerMetric.Type.Power(
                    mapOf(
                        PowerCategory.CPU to PowerCategoryDisplayLevel.TOTAL,
                        PowerCategory.DISPLAY to PowerCategoryDisplayLevel.TOTAL,
                        PowerCategory.GPU to PowerCategoryDisplayLevel.TOTAL,
                        PowerCategory.NETWORK to PowerCategoryDisplayLevel.TOTAL,
                    )
                )),
                // Measure custom trace sections by name EntryRow (which is added to the EntryRow composable).
                // Mode.Sum measures combined duration and also how many times it occurred in the trace.
                // This way, you can estimate whether a composable recomposes more than it should.
                TraceSectionMetric("EntryRowCustomTrace", TraceSectionMetric.Mode.Sum),
                // This trace section takes into account the SQL wildcard character %,
                // which can find trace sections without the full name.
                // This way, you can measure composables produced by the composition tracing
                // and measure how long they took and how many times they recomposed.
                // WARNING: This metric only shows results when running with composition tracing, otherwise it won't be visible in the outputs.
                TraceSectionMetric("%EntryRow%", TraceSectionMetric.Mode.Sum),
            ),
            // Try switching to different compilation modes to see the effect
            // it has on frame timing metrics.
            compilationMode = CompilationMode.None(),
            startupMode = StartupMode.WARM, // restarts activity each iteration
            iterations = DEFAULT_ITERATIONS,
            // [END_EXCLUDE]
            setupBlock = {
                uiAutomator {
                    // Before starting to measure, navigate to the UI to be measured.
                    startIntent(Intent("$packageName.COMPOSE_ACTIVITY"))
                }
            }
        ) {
            uiAutomator {
                onElement { isScrollable }.fling(Direction.DOWN)
            }
        }
    }

В примере ниже EntryRowCustomTrace представляет собой раздел пользовательской трассировки, определенный внутри слоев composable-элементов с помощью стандартной обертки блока Kotlin trace(sectionName) { ... }. Чтобы предоставить данные для TraceSectionMetric, необходимо обернуть целевые компоненты пользовательского интерфейса в рабочую базу кода приложения с помощью стандартной обертки блока среды выполнения Jetpack trace:

@Composable
private fun EntryRow(entry: Entry, modifier: Modifier = Modifier) = trace("EntryRowCustomTrace") {
    Card(modifier = modifier) {
        Row(verticalAlignment = Alignment.CenterVertically) {
            Text(
                text = entry.contents,
                modifier = Modifier
                    .padding(16.dp)
                    .wrapContentSize()
            )

            Spacer(modifier = Modifier.weight(1f))

            Checkbox(
                checked = false,
                onCheckedChange = {},
                modifier = Modifier.padding(16.dp)
            )
        }
    }
}

Результаты тестирования выводятся на вкладке Benchmark (Тестирование) в терминале Android Studio, как показано на рисунке 1. Если определено несколько показателей, все их вычисленные элементы объединяются в окне сводки.

Результаты TraceSectionMetric и FrameTimingMetric.
Рисунок 1. Объединенные результаты консоли TraceSectionMetric и FrameTimingMetric для современного макета Compose.

Ниже подробно описаны StartupTimingMetric, FrameTimingMetric, TraceSectionMetric и PowerMetric. Полный список доступных показателей контрольных значений приведен в подклассах Metric в документации по API.

StartupTimingMetric

StartupTimingMetric регистрирует показатели времени запуска приложения со следующими значениями:

  • timeToInitialDisplayMs – время с момента, когда система получает намерение запуска, до момента, когда она отрисовывает первый кадр целевого экрана.
  • timeToFullDisplayMs – время с момента, когда система получает намерение запуска, до момента, когда приложение сообщает о полной отрисовке с помощью внутренних механизмов платформы. Измерение прекращается после завершения отрисовки первого кадра, который содержит сигнал о полной отрисовке или следует за ним.

StartupTimingMetric выводит минимальное, медианное и максимальное значения из итераций запуска. Чтобы оценить улучшение запуска, всегда ориентируйтесь на медианные значения, поскольку они дают наилучшую оценку типичного времени запуска у пользователей.

В архитектуре Compose-first не пытайтесь вызвать activity.reportFullyDrawn вручную. Вместо этого используйте безопасные для Compose асинхронные утилиты ReportDrawn, ReportDrawnWhen или ReportDrawnAfter внутри composable-функций экрана, чтобы автоматически сообщать Macrobenchmark о завершении отрисовки асинхронных сетевых данных или сложных состояний интерфейса.

Подробнее об анализе и оптимизации времени запуска приложения…

FrameTimingMetric

FrameTimingMetric фиксирует точную информацию о времени из кадров, созданных в ходе контрольного пути, например при прокрутке списка или сложной анимации макета пользовательского интерфейса, и выводит следующие диагностические значения:

  • frameOverrunMs: время, на которое кадр задерживается. Положительные числа указывают на пропущенный кадр, сопровождаемый видимым заиканием или заиканием. Отрицательные числа показывают, насколько быстрее был сформирован кадр по сравнению с аппаратным ограничением подсистемы. Примечание. Этот показатель доступен только в Android 12 (уровень API 31) и более поздних версиях.
  • frameDurationCpuMs – время, в течение которого кадр активно создавался на ЦП в основном потоке UI приложения и RenderThread.

Эти измерения собираются в распределении 50-го, 90-го, 95-го и 99-го процентилей:

frameDurationCpuMs P50 3.5, P90 6.0, P95 6.4, P99 11.0
frameOverrunMs P50 -11.6, P90 -7.2, P95 -7.1, P99 -1.2

При оптимизации иерархий макетов Jetpack Compose обратите внимание на кадры с наихудшей производительностью (границы P95 и P99). Если frameOverrunMs резко возрастает до положительных целых чисел в высоких процентилях, это указывает на то, что рекомпозиции задерживают основной поток во время тяжелых анимаций прокрутки.

Подробную информацию о том, как выявлять и устранять медленные кадры, можно найти в статье Производительность Jetpack Compose.

TraceSectionMetric

TraceSectionMetric фиксирует, сколько раз выполняется определенный раздел трассировки и сколько времени на это уходит. Для отслеживания времени он выводит минимальное, среднее и максимальное время в миллисекундах. Целевой раздел трассировки определяется либо вызовом функции trace(sectionName), либо границами блока более низкого уровня между Trace.beginSection(sectionName) и Trace.endSection() или их асинхронными вариантами.

EntryRowCustomTraceCount min 20.0, median 28.0, max 50.0
EntryRowCustomTraceSumMs min 34.9, median 44.4, max 66.6

По умолчанию показатель выводит только разделы трассировки, скомпилированные непосредственно из двоичных файлов пакета вашего приложения. Чтобы включить процессы, запущенные за пределами пакета приложения, задайте свойство targetPackageOnly = false.

При работе с Jetpack Compose Runtime Tracing вы можете отображать отдельные composable-функции на графиках трассировки системы, не создавая вручную оболочки трассировки. Для этого включите трассировку композиции.

Добавления зависимости androidx.compose.runtime:runtime-tracing в целевое приложение достаточно для трассировки профилировщика вручную. Чтобы программно фиксировать эти трассировки в рамках запуска Macrobenchmark, требуется дополнительная настройка в модуле тестирования.

Полные инструкции по настройке можно найти в статье Как записать трассировку с помощью Jetpack Macrobenchmark.

PowerMetric

PowerMetric фиксирует изменение мощности или энергии за время выполнения макротеста. Каждая выбранная категория разбивается на измеряемые аппаратные компоненты, а невыбранные категории группируются в сегмент "Не выбрано".

Требования к оборудованию. Эти показатели отражают потребление ресурсов на уровне системы, а не отдельных приложений. Поэтому сбор данных ограничен физическими устройствами Google Pixel 6, Pixel 6 Pro и более новыми моделями.

Для каждой категории показатель содержит два значения:

  • power<category>Uw – количество энергии, потребленной за время тестирования в этой категории (измеряется в микроваттах).
  • energy<category>Uws – общее количество энергии, переданной за единицу времени в течение теста в этой категории (измеряется в микроватт-секундах).

Категории включают:

  • CPU
  • DISPLAY
  • GPU
  • GPS
  • MEMORY
  • MACHINE_LEARNING
  • NETWORK
  • UNCATEGORIZED

В некоторых категориях, например CPU, может быть сложно отделить работу, выполненную другими процессами, от работы, выполненной вашим приложением. Чтобы свести к минимуму помехи, удалите или ограничьте ненужные приложения и аккаунты.

powerCategoryCpuUw min 300.2, median 346.1, max 519.6
powerCategoryDisplayUw min 319.8, median 325.8, max 329.7
powerCategoryGpuUw min 18.8, median 23.3, max 36.9
powerCategoryNetworkUw min 97.3, median 123.3, max 681.3
powerTotalUw min 1234.8, median 1316.6, max 2112.4
powerUnselectedUw       min  483.3,  median  512.6,  max  561.7

Анализ основных подсистем

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

Выходные данные терминала сопоставляются с запрошенной конфигурацией:

  • powerCategoryCpuUw – количество энергии, потребленной ЦП за время теста.
  • powerCategoryGpuUw – количество энергии, потребленной графическим процессором за время теста.
  • powerUnselectedUw – совокупная мощность, потребляемая всеми доступными категориями оборудования, которые не были явно запрошены в вашей карте инициализации.

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

Дополнительные ресурсы

Просмотр контента