Эталон непрерывной интеграции

Вы можете запускать тесты в непрерывной интеграции (CI), чтобы отслеживать производительность с течением времени и распознавать снижение или улучшение производительности еще до того, как ваше приложение будет выпущено. На этой странице представлена ​​основная информация о бенчмаркинге в CI.

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

Нечеткие результаты

Хотя эталонные тесты представляют собой инструментальные тесты, результаты — это не просто «пройдено или не пройдено». Тесты предоставляют измерения времени для данного устройства, на котором они работают. Построение графиков результатов с течением времени позволяет отслеживать изменения и наблюдать шум в измерительной системе.

Используйте реальные устройства

Запустите тесты на физических устройствах Android. Хотя они могут работать на эмуляторах, это настоятельно не рекомендуется, поскольку это не отражает реалистичного пользовательского опыта и вместо этого предоставляет цифры, привязанные к операционной системе хоста и возможностям оборудования. Рассмотрите возможность использования реальных устройств или сервиса, позволяющего запускать тесты на реальных устройствах, например Firebase Test Lab .

Запустите тесты

Запуск тестов в рамках конвейера CI может отличаться от его локального запуска из Android Studio. Локально вы обычно запускаете интеграционные тесты Android с помощью одной задачи Gradle connectedCheck . Эта задача автоматически создает ваш APK и тестовый APK, а также запускает тесты на устройствах, подключенных к серверу CI. При работе в CI этот поток обычно необходимо разделить на отдельные фазы.

Строить

Для библиотеки Microbenchmark запустите задачу Gradle assemble[VariantName]AndroidTest , которая создаст тестовый APK, содержащий как код вашего приложения, так и тестируемый код.

Альтернативно, библиотека Macrobenchmark требует, чтобы вы создали целевой APK и протестировали APK отдельно. Поэтому запустите задачи Gradle :app:assemble[VariantName] и :macrobenchmark:assemble[VariantName] .

Установите и запустите

Эти шаги обычно выполняются без необходимости запуска задач Gradle. Обратите внимание: они могут быть абстрагированы в зависимости от того, используете ли вы службу, позволяющую запускать тесты на реальных устройствах.

Для установки используйте команду adb install и укажите тестовый APK или целевой APK.

Запустите команду adb shell am Instrument, чтобы запустить все тесты:

adb shell am instrument -w com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner

При использовании библиотеки Macrobenchmark используйте обычный androidx.test.runner.AndroidJUnitRunner в качестве средства запуска инструментов.

Вы можете передать те же аргументы инструментария, что и в конфигурации Gradle, используя аргумент -e . Все параметры аргументов инструментария см. в разделе «Аргументы инструментария Microbenchmark» или «Добавление аргументов инструментария для Macrobenchmark».

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

adb shell am instrument -w -e "androidx.benchmark.dryRunMode.enable" "true" com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner

Дополнительную информацию о том, как запускать инструментальные тесты из командной строки, см. в разделе «Выполнение тестов с помощью ADB» .

Блокировка часов

Плагин Microbenchmark Gradle предоставляет команду ./gradlew lockClocks для блокировки тактовой частоты процессора корневого устройства. Это полезно для обеспечения стабильности, когда у вас есть доступ к корневым устройствам, например, к сборкам «userdebug». Вы можете повторить это с помощью сценария оболочки lockClocks.sh , доступного в исходном коде библиотеки .

Вы можете либо запустить сценарий непосредственно с хоста Linux или Mac, либо отправить его на устройство с помощью нескольких команд adb:

adb push path/lockClocks.sh /data/local/tmp/lockClocks.sh
adb shell /data/local/tmp/lockClocks.sh
adb shell rm /data/local/tmp/lockClocks.sh

Если вы запускаете сценарий оболочки непосредственно на хосте, он отправляет эти команды на подключенное устройство.

Дополнительную информацию о том, почему полезно блокировать тактовую частоту ЦП, см. в разделе «Как получить согласованные тесты» .

Соберите результаты

Библиотеки тестирования выводят измерения в формате JSON , а также профилируют трассировки в каталог на устройстве под управлением Android после каждого запуска теста. Библиотека Macrobenchmark выводит несколько файлов трассировки perfetto: по одному на каждую измеренную итерацию каждого цикла MacrobenchmarkRule.measureRepeated . Однако Microbenchmark создает только один файл трассировки для всех итераций каждого BenchmarkRule.measureRepeated . Файлы трассировки профилирования также выводятся в этот же каталог.

Сохраните и найдите файлы

Если вы запускаете тесты с помощью Gradle, эти файлы автоматически копируются в каталог выходов вашего главного компьютера в build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/ .

Если вы запускаете напрямую с помощью команды adb , вам необходимо извлечь файлы вручную. По умолчанию отчеты сохраняются на устройстве в медиакаталоге внешнего хранилища тестируемого приложения. Для удобства библиотека печатает путь к файлу в Logcat. Обратите внимание, что выходная папка может отличаться в зависимости от версии Android, на которой выполняются тесты.

Benchmark: writing results to /storage/emulated/0/Android/media/com.example.macrobenchmark/com.example.macrobenchmark-benchmarkData.json

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

adb shell am instrument -w -e additionalTestOutputDir /sdcard/Download/ com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner

В Android 10 (уровень API 29) и более поздних версиях тесты вашего приложения по умолчанию выполняются в изолированной программной среде хранилища, что предотвращает доступ вашего приложения к файлам за пределами каталога, специфичного для приложения. Чтобы иметь возможность сохранять в глобальный каталог, например /sdcard/Download , передайте следующий аргумент инструментария:

-e no-isolated-storage true

Вы также должны явно разрешить устаревшие варианты хранения в манифесте вашего теста:

<application android:requestLegacyExternalStorage="true" ... >

Дополнительные сведения см. в разделе Временный отказ от хранилища с заданной областью .

Получить файлы

Чтобы получить сгенерированные файлы с устройства, используйте команду adb pull , которая переносит указанный файл в текущий каталог на вашем хосте:

adb pull /storage/emulated/0/Android/media/com.example.macrobenchmark/com.example.macrobenchmark-benchmarkData.json

Чтобы получить все benchmarkData из указанной папки, проверьте следующий фрагмент:

# The following command pulls all files ending in -benchmarkData.json from the directory
# hierarchy starting at the root /storage/emulated/0/Android.
adb shell find /sdcard/Download -name "*-benchmarkData.json" | tr -d '\r' | xargs -n1 adb pull

Файлы трассировки ( .trace или .perfetto-trace ) сохраняются в той же папке, что и benchmarkData.json , поэтому вы можете собирать их таким же образом.

Пример контрольных данных

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

{
    "context": {
        "build": {
            "brand": "google",
            "device": "blueline",
            "fingerprint": "google/blueline/blueline:12/SP1A.210812.015/7679548:user/release-keys",
            "model": "Pixel 3",
            "version": {
                "sdk": 31
            }
        },
        "cpuCoreCount": 8,
        "cpuLocked": false,
        "cpuMaxFreqHz": 2803200000,
        "memTotalBytes": 3753299968,
        "sustainedPerformanceModeEnabled": false
    },
    "benchmarks": [
        {
            "name": "startup",
            "params": {},
            "className": "com.example.macrobenchmark.startup.SampleStartupBenchmark",
            "totalRunTimeNs": 4975598256,
            "metrics": {
                "timeToInitialDisplayMs": {
                    "minimum": 347.881076,
                    "maximum": 347.881076,
                    "median": 347.881076,
                    "runs": [
                        347.881076
                    ]
                }
            },
            "sampledMetrics": {},
            "warmupIterations": 0,
            "repeatIterations": 3,
            "thermalThrottleSleepSeconds": 0
        }
    ]
}

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

{% дословно %} {% дословно %} {% дословно %} {% дословно %}