На ранней стадии разработки мы, Android-разработчики, не спешим задумываться об оптимизации производительности будущего приложения. Этому есть объяснение: преждевременная оптимизация невыгодна бизнесу на первых порах, когда в приоритете высокая скорость создания жизнеспособного продукта при условии минимальных затрат. Однако, однажды оптимизация производительности становится просто необходимой.
Поскольку тема оптимизации производительности Android-приложений достойна целого цикла статей, сегодня рассмотрим лишь один ее аспект ― бенчмаркинг.
В статье разберемся с тем, что за зверь такой этот бенчмаркинг и для чего он нужен, а также получим базовые знания для написания первого бенчмарк-теста. Помогать в этом деле буду я, Диана Федотова, Android-разработчица в Технократии.
Содержание
Что такое бенчмаркинг
Наивная реализация бенчмаркинга
Библиотека Jetpack Benchmark
Макробенчмарки
Микробенчмарки
Краткие выводы
Что есть бенчмаркинг
Оптимизация производительности приложения, как мы уже говорили выше, ― задача комплексная. Она может включать в себя различные действия, для каждого из которого существуют свои подходы и инструменты.
Google разбивает эту задачу на три этапа: inspect, improve, monitor. Вместе они образуют замкнутый цикл.
Один из методов, используемых на этапе inspect, ― бенчмаркинг. Бенчмаркингом называют тестирование производительности программного кода. С помощью бенчмарк-тестов выявляют просадки производительности и анализируют то, как новый код аффектит на работу кода существующего.
Нативная реализация бенчмаркинга
Давайте представим ситуацию: мы обнаружили проблемы с производительностью нашего приложения. Причину выяснили ― некий фрагмент кода выполняется чересчур длительное время. Пусть этот код лежит методе doSomeWork. Мы отрефакторили его, а теперь хотим проверить, стал ли этот фрагмент кода выполняться быстрее.
В первом приближении задача кажется довольно простой: измерим время выполнения метода до и после правок, обернем в тест. Это и будет являться бенчмаркингом.
Пишем первое, наивное решение для вычисления времени выполнения doSomeWork. Вычитаем время начала работы метода из времени окончания. Предельно просто, должно работать.
Запускаем тест один раз, запускаем тест еще раз и обнаруживаем проблему: мы получаем разные результаты при каждом перезапуске одного и того же теста. Что ж, нужно повышать точность. Для этого оборачиваем измерение в цикл, выполняем вызов метода несколько раз и находим среднее значение времени выполнения.
Работает, и, кажется, работает немного поточнее. Но и к такому решению есть некоторые вопросы. Почему мы проводим именно 5 измерений? Как правильно выбирать это число? Как обрабатывать различные выбросы в измерениях? Как учитывать состояние системы и нагрузку на нее, а также влияние задач, выполняющихся в фоне, ведь все это может влиять на результат измерений?
Пока неясно. Ясно лишь одно: провести эти вычисления руками — задача нетривиальная. Наше наивное решение:
неточно;
нестабильно.
Значит, нужен автоматизированный подход для измерения производительности кода. Решение есть — воспользуемся библиотекой Jetpack Benchmark