Источник: Nuances of Programming
Введение
В процессе разработки часто возникает потребность протестировать в браузере производительность приложения. Такое тестирование способствует обнаружению потенциальных ошибок, замедляющих его работу. В данной статье вашему вниманию будет предложен способ тестирования производительности в Chrome.
Образец приложения
В нашем случае используется простое приложение, включающее в себя панель приложения, плавающую кнопку действия и бесконечный список элементов, который также показывает число нажатий кнопки.
У приложения есть вторая страница, содержащая определенную информацию.
Скопировать приложение можно здесь:
Что будем тестировать?
Наша цель — протестировать производительность приложения в следующих сценариях использования:
- Пользователь прокручивает бесконечный список.
- Пользователь переключается между двумя страницами.
- Пользователь нажимает плавающую кнопку действия.
Установка фреймворка
К pubspec.yaml добавьте следующее:
Эта зависимость входит в минимальный пакет web_benchmarks_framework, выполняющий тестирование производительности в Chrome.
Он сформирован из macrobenchmarks и devicelab — двух пакетов, используемых Flutter для веб-тестирования производительности во Flutter Gallery. В настоящее время оба этих пакета применяются для аналогичного тестирования во flutter/flutter, поэтому проще импортировать более общий пакет web_benchmarks_framework.
Выполните flutter pub get, чтобы присоединить этот пакет.
Написание первого теста
Под lib добавьте директорию benchmarks, а к ней — файл .dart с именем runner.dart:
Содержит этот файл следующее:
Что делает этот тест?
- При запуске этого приложения создается объект ScrollRecorder, который управляет приложением, выполняя автоматические жесты. В нашем случае он начинает прокручивать бесконечный список.
- Класс ScrollRecorder расширяет класс AppRecorder, в свою очередь расширяющий класс WidgetRecorder, который по мере управления приложением также записывает показатели производительности.
- runBenchmarks — это функция, определяемая в package:web_benchmarks_framework/driver.dart, которая позволяет пользователю выбрать, какой тест выполнять, и отображает результаты в браузере.
- Метод automate использует пакет flutter_test, предоставляющий способы выполнения жестов или поиска определенных виджетов в приложении.
Выполнение первого теста
В корневой директории проекта выполните flutter run -d chrome -t lib/benchmarks/runner.dart. Таким образом вы укажите Flutter использовать в качестве входной точки не main.dart, а runner.dart.
На данный момент у нас есть всего один тест производительности, так что запустите его нажатием “scroll”.
После запуска теста список начинает автоматически прокручиваться вниз.
Спустя несколько секунд тест заканчиваетсяи выводит на экран следующий результат:
Этот график показывает время, затраченное приложением на отрисовку каждого (зарегистрированного) кадра. Горизонтальная ось отображает ход времени, а вертикальная — продолжительность каждого кадра.
Первые 2/3 графика окрашены в серый фон — эти кадры считаются “подготовительными” и в статистику не включаются. Такие кадры обычно обеспечивают JIT-компилятору время для компиляции кода и заполняют различные кэши, чтобы показатели измеренных кадров отражали “итоговую” производительность приложения, а не только первых секунд его работы. Тем не менее подготовительным этапом не всегда следует пренебрегать, поскольку он может предоставить ценную информацию о производительности приложения в течение первых секунд его выполнения, благодаря чему уже можно будет делать выводы о его работоспособности.
Красные кадры — это “выбросы”, отрисовка которых требует гораздо больше времени. Некоторые из них могут быть почти незаметными. Например, до определенного момента не будет видно подвисаний в начале или конце анимации. А вот заторможенный кадр в середине анимации будет сложно не заметить.
Выбросы служат хорошим индикатором имеющихся неполадок. Дорабатывая приложение, вы можете уменьшить значения выбросов или сократить их число, что будет свидетельствовать о повышении его плавности.
Сбор данных из Chrome DevTools
Данный тест производительности полностью выполняется внутри Chrome. Добавьте следующий файл в качестве test/run_benchmarks.dart:
Затем запустите dart test/run_benchmarks.dart.
Спустя минуту вы увидите следующие результаты:
Точные значения теста производительности могут варьироваться в зависимости от компьютера.
Что делает этот тест?
- При выполнении test/run_benchmarks.dart собирается веб-приложение, затем запускается экземпляр Chrome, в котором это приложение выполняется.
- После этого test/run_benchmarks.dart соединяется с портом Chrome DevTools, собирая и извлекая из него соответствующие показатели производительности.
Что означают результаты теста?
- “Preroll” — это первый обход. Он ничего не отображает, но вычисляет значения, которые позже используются для отрисовки. Примеры включают: матрицы преобразований, обратные преобразования и обрезку кадров.
- “Apply frame” — это второй обход, при котором отображается UI.
- “Draw frame” — это общее время, необходимое фреймворку для отображения кадра. Этот этап включает “Preroll” и “Apply frame”, а также время, затраченное на создание и расположение виджетов.
- “Total UI frame” включает все составляющие компоненты “Draw frame”, а также скрытую работу, выполняемую браузером: обновления дерева слоев, пересчет стилей и браузерный макет (не путать с собственным макетом Flutter).
- Когда набор данных (список временных интервалов) собран, алгоритм удаляет выбросы.
- Сначала вычисляются среднее и стандартное отклонения данных, и любая точка данных, превышающая эти значения (среднее + 1 стандартное отклонение), считается выбросом.
- Затем с помощью среднего и стандартного отклонения данных без выбросов (чистых данных) вычисляются средние значения и шум всего набора, которые впоследствии сообщаются.
- Кроме того, сообщается средний показатель всех выбросов, а также отношение этого показателя к чистым данным.
- Показатели “outlierRatio” и “noise” для каждого набора данных отчетливо указывают, сколько шума содержится в производительности приложения. Наличие чрезмерного шума свидетельствует о проблемах с последовательностью выполнения (например, торможение кадров в результате задержек сборки мусора). Уменьшив шум, вы сможете повысить плавность работы приложения.
Добавляем больше тестов
Отредактируйте lib/benchmarks/runner.dart, чтобы добавить еще два теста.
Сначала измените функцию main:
Затем добавьте еще два класса, расширяющих AppRecorder:
Что делают эти тесты?
- Мы добавили два оставшихся теста: один проверяет переключение между страницами, другой — касание плавающей кнопки действия.
- animationStops систематически контролирует выполнение анимации и останавливается по мере ее полного прекращения. Это гарантирует, например, успешный переход на страницу “about”.
- В тестах для проверки “page” и “tap” логический тип _completed отслеживает завершение автоматических жестов.
- В указанных тестах переопределение метода shouldContinue приводит к тому, что AppRecorder останавливает запись кадров после завершения всех жестов.
Как выполнять эти тесты?
Для запуска этих тестов (и просмотра анимации) в Chrome выполните:
- flutter run -d chrome -t lib/benchmarks/runner.dart --profile.
Для запуска данных тестов и сбора данных DevTools выполните:
- dart test/run_benchmarks.dart.
Что дальше?
Теперь, владея способом сбора данных производительности, вы можете использовать его по своему усмотрению:
- Вы можете настроить задачу в CI, запускающую эти тесты производительности каждый раз, как кто-нибудь отправляет PR, чтобы избежать внесения изменений, сильно влияющих на производительность.
- Вы также можете настроить информационную панель, отслеживающую тенденции тестов производительности.
Читайте также:
Перевод статьи Tianguang Zhang: Performance testing on the web