На первый взгляд обычная логика обновления списка может постоянно поддерживать активность CPU. Слишком частые таймеры, повторные сетевые запросы и фоновые задачи также способны увеличить количество пробуждений системы. Функциональные тесты обычно не обнаруживают таких проблем, а покрытие кода не указывает на них. Чтобы выявлять подобные изменения до слияния, можно зафиксировать тестовую среду на облачном Mac от OVPS, записать одну и ту же последовательность пользовательских действий с помощью xctrace, а затем сравнить результаты с подтверждённой базовой линией.
Сначала определите, что измеряет контроль
Энергопотребление нельзя свести к одному значению вне контекста конкретного сценария. Бездействие на главном экране, непрерывная прокрутка, декодирование изображений и фоновая синхронизация имеют совершенно разные профили использования ресурсов, поэтому их нельзя объединять в одну базовую линию. Сначала выберите ключевой сценарий длительностью от 60 до 120 секунд, который можно стабильно воспроизводить. Например: запустить приложение, перейти к списку сообщений, прокрутить три экрана, открыть подробности и вернуться назад.
Для каждого сценария необходимо зафиксировать как минимум следующие условия:
- коммит приложения и конфигурацию сборки;
- модель устройства, версию системы и диапазон заряда аккумулятора;
- яркость экрана, тип сети и состояние режима энергосбережения;
- объём данных тестовой учётной записи;
- продолжительность измерения, количество прогревочных и основных запусков.
Симулятор подходит для проверки сценариев автоматизации и стабильности действий, но не отражает энергопотребление физического устройства. Основной контроль должен выполняться на закреплённом реальном устройстве. Результаты симулятора можно использовать только как дополнительные данные об активности процесса.
Не используйте результаты первого запуска. При первом старте могут выполняться миграция базы данных, подготовка шейдеров или заполнение кеша. Сначала проведите один прогревочный запуск, затем запишите как минимум три основных запуска и используйте медиану, чтобы снизить влияние случайных системных задач.
Зафиксируйте состояние облачного Mac и тестового устройства
На исполнительном узле должна быть закреплена основная версия Xcode, а каталог разработчика необходимо выбирать явно. Не полагайтесь на переменные окружения, которые случайно оказались активны в интерактивной оболочке.
set -euo pipefail
export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
xcodebuild -version
xcrun xctrace version
xcrun xctrace list devices
xcrun xctrace list templates
Последние две команды одновременно служат проверкой совместимости. Набор доступных шаблонов и структура экспорта могут меняться между версиями Xcode, поэтому сценарий не должен предполагать, что Energy Log присутствует всегда. Если шаблон не найден, выполнение следует немедленно прекратить, сохранив сведения о версии, а не переходить к бессмысленному пустому измерению.
Перед началом физическое устройство необходимо привести к одинаковому состоянию: закрыть посторонние приложения, обеспечить сопоставимый диапазон заряда, дождаться нормализации температуры, отключить автоматические обновления и стабилизировать сетевые условия. Во время тестирования нельзя одновременно выполнять архивирование, загрузку зависимостей или очистку диска. Дополнительная нагрузка на общем узле искажает показатели CPU и I/O.
Настройте предварительную проверку
Сохраняйте UDID устройства, Bundle ID, название сценария и идентификатор коммита в одном каталоге запуска. Имя каталога должно быть уникальным, но не должно содержать токены или материалы для подписи, чтобы они не попали в пути и журналы.
RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)-${GIT_COMMIT:-local}"
OUT_DIR="artifacts/energy/${RUN_ID}"
mkdir -p "$OUT_DIR"
xcrun simctl list devices > "$OUT_DIR/devices.txt"
xcrun xctrace list templates > "$OUT_DIR/templates.txt"
git rev-parse HEAD > "$OUT_DIR/commit.txt"
При подключении физического устройства первую команду можно заменить принятой в команде командой обнаружения устройств. Важна не форма команды, а остановка измерения при ошибке. Иначе состояние «устройство не подключено» может быть ошибочно принято за «энергопотребление снизилось».
Записывайте воспроизводимые трассировки xctrace
Сначала запустите исследуемый процесс и завершите прогрев, а затем подключитесь к нему по имени процесса. В приведённом ниже сценарии устройство, процесс и шаблон должны быть явно переданы через параметры CI:
DEVICE_UDID="${DEVICE_UDID:?missing DEVICE_UDID}"
PROCESS_NAME="${PROCESS_NAME:?missing PROCESS_NAME}"
TRACE="$OUT_DIR/energy.trace"
xcrun xctrace record \
--template "Energy Log" \
--device "$DEVICE_UDID" \
--attach "$PROCESS_NAME" \
--time-limit 90s \
--output "$TRACE"
После начала записи автоматизация UI должна выполнить фиксированную последовательность действий. В сценарии действий следует использовать идентификаторы доступности, а не экранные координаты. Тестовые данные необходимо загрузить заранее, а сетевые запросы желательно направлять в стабильную тестовую среду. Если во время запуска не удалось войти в систему, всплывающее окно перекрыло интерфейс или нужная страница не была открыта, такой запуск следует пометить как недействительный и не учитывать при расчёте медианы.
Успешное завершение xctrace означает только то, что трассировка создана, но не подтверждает правильное выполнение сценария. Для каждой записи также необходимо сохранять результаты UI-теста, время начала и завершения, сводку журналов приложения и отметку о завершении сценария. Если отсутствует хотя бы один из этих элементов, контроль должен сообщить «измерение недействительно», а не считать проверку производительности пройденной.
Экспортируйте метрики и сравните их с базовой линией
Сначала экспортируйте структуру каталога трассировки, выясните, какие таблицы предоставляет текущая версия Xcode, а затем поддерживайте отдельные правила разбора для этой версии:
xcrun xctrace export \
--input "$TRACE" \
--toc \
--output "$OUT_DIR/toc.xml"
Не следует разбирать бинарную трассировку напрямую с помощью одного ненадёжного регулярного выражения. Более устойчивый подход — хранить XPath-выражения или XML-парсеры для каждой основной версии Xcode и архивировать исходную трассировку вместе с результатами. Контроль может отслеживать четыре типа изменений: постоянную активность CPU, пробуждения потоков, частоту срабатывания таймеров и объём сетевой передачи. Эти показатели служат ориентирами для диагностики, поэтому их не следует механически объединять в единую «оценку энергопотребления».
Базовая линия формируется из нескольких штатных запусков на одном устройстве, для одного сценария и одного типа сборки. Рекомендуется сохранять медиану последней подтверждённой версии вместе со всеми исходными значениями отдельных запусков. При сравнении нужно одновременно учитывать относительное изменение и абсолютный нижний порог: даже удвоение очень малого значения не обязательно имеет инженерное значение.
Обрабатывайте отклонения по уровням
Небольшое отклонение сначала должно вызывать предупреждение, не блокируя слияние. Проверку следует завершать с ошибкой, только если порог превышен несколько раз подряд либо одновременно ухудшились показатели CPU и пробуждений. Пороговые значения необходимо определять по историческим данным команды, а не копировать универсальный процент.
Отчёт об ошибке должен содержать как минимум идентификатор коммита, модель устройства и версию системы, значения трёх измерений, медиану, базовую линию, относительное изменение, путь к трассировке и результат UI-сценария. Тогда разработчик сможет сразу открыть подтверждающие материалы, а не получить только сообщение «энергопотребление слишком высокое».
Переходите от аномальной трассировки к коду
Если активность CPU остаётся повышенной, сначала проверьте опрос в главном потоке, обработку изображений, повторные вычисления компоновки и незавершённые фоновые очереди. При росте количества пробуждений обратите особое внимание на таймеры с коротким интервалом, частую запись на диск, дублирующиеся уведомления и необъединённые повторные сетевые запросы. При аномальной сетевой активности следует проверить запросы пагинации, попадания в кеш, пакеты телеметрии и стратегию переподключения.
Типичные причины ложных выводов также нужно исключать отдельно: изменение температуры после зарядки устройства, продолжающееся заполнение кеша при первом запуске, изменение объёма данных тестовой учётной записи, прерывание сценария системным окном и параллельное выполнение других ресурсоёмких задач на облачном Mac. После исправления необходимо повторно выполнить все три запуска в тех же условиях. Нельзя заменять запись о неудачной проверке одним более удачным результатом.
Ценность контроля регрессий энергопотребления заключается не в создании красивой итоговой оценки, а в связывании тестового сценария, состояния устройства, исходных трассировок и коммита кода. Только если эти данные можно собирать воспроизводимо, у аномалии появляется однозначный источник, а сам контроль не превращается в шум, который регулярно обходят.
Часто задаваемые вопросы
Можно ли измерять энергопотребление только в симуляторе iOS?
Нет. Симулятор подходит для проверки сценария и скриптов, но итоговую базовую линию следует получать на физическом устройстве фиксированной модели и версии системы.
Нужно ли блокировать слияние после одного превышения порога?
Нет. Выполните не менее трёх запусков, сравните медиану с базовой линией и блокируйте слияние только при устойчивом отклонении с сохранённым trace-файлом.
Перенесите следующую сборку на выделенный физический узел
Выберите одну из трёх конфигураций Apple Silicon и шести доступных узлов. Фактический статус доступности отображается в консоли в реальном времени.