Если один и тот же коммит последовательно собирается на Mac в облаке за 11 минут в первый раз и за 15 минут в четвёртый, не стоит сразу делать вывод о «нестабильной производительности машины». Похожую динамику могут вызвать попадания в кэш, процессы индексирования, параллельный запуск тестов и тепловая нагрузка. Правильный подход — зафиксировать переменные, выполнить серию измерений и только затем проверить, совпадает ли рост времени сборки с увеличением энергопотребления и теплового давления.
Сначала определите воспроизводимый образец сборки
Объектом диагностики должна быть стабильно воспроизводимая команда, а не Scheme, которую разработчик запускает вручную. Зафиксируйте коммит, путь к Xcode, SDK, цель, конфигурацию сборки и каталог DerivedData, а также запишите, сколько времени машина бездействовала после запуска. Если перед каждым прогоном переключать ветку или обновлять зависимости, измерения будут отражать лишь изменение рабочей нагрузки.
На выделенных физических узлах VMOrbit ресурсы хоста не зависят от планирования виртуальных машин других арендаторов. Однако внутри самого узла по-прежнему возможна конкуренция между индексированием, разрешением зависимостей, симуляторами и оставшимися процессами предыдущих сборок. Перед началом сохраните основные сведения об окружении:
mkdir -p "$HOME/build-thermal-check"
system_profiler SPHardwareDataType > "$HOME/build-thermal-check/hardware.txt"
xcodebuild -version > "$HOME/build-thermal-check/xcode.txt"
pmset -g > "$HOME/build-thermal-check/power.txt"
ps -axo pid,%cpu,%mem,etime,command > "$HOME/build-thermal-check/processes-before.txt"
Измеряйте холодные и тёплые сборки отдельно
Холодная сборка показывает нагрузку полной компиляции, а тёплая — работу инкрементального сценария. Объединять их в одну статистическую выборку нельзя. Для холодной сборки следует использовать новый отдельный каталог DerivedData, а для тёплой — повторно применять каталог предыдущего прогона. Не очищайте глобальные кэши, чтобы не повлиять на другие задачи на узле.
| Образец | DerivedData | Основное назначение |
|---|---|---|
| Холодная сборка | Создаётся заново для каждой серии | Сравнение длительной нагрузки при полной компиляции |
| Тёплая сборка | Повторно используется в одной серии | Проверка инкрементальной сборки и эффективности кэша |
| Контроль без нагрузки | Сборка не выполняется | Выявление фоновых процессов и базового энергопотребления |
Одновременно собирайте данные о времени и тепловом давлении
Одного общего времени выполнения недостаточно, чтобы доказать тепловой троттлинг. Выполните не менее трёх последовательных прогонов и во время сборки параллельно собирайте данные с помощью powermetrics. Для этой утилиты обычно требуются права администратора, поэтому разрешение следует ограничить конкретной командой и явно заданными параметрами.
RUN_ROOT="$HOME/build-thermal-check/run-01"
mkdir -p "$RUN_ROOT/DerivedData"
sudo powermetrics --samplers cpu_power -i 1000 -n 900 \
-o "$RUN_ROOT/powermetrics.txt" &
METRIC_PID=$!
/usr/bin/time -lp xcodebuild \
-workspace App.xcworkspace \
-scheme App \
-configuration Release \
-destination 'generic/platform=iOS' \
-derivedDataPath "$RUN_ROOT/DerivedData" \
build > "$RUN_ROOT/build.log" 2> "$RUN_ROOT/time.txt"
wait "$METRIC_PID"
pmset -g therm > "$RUN_ROOT/thermal.txt"
Параметр -n 900 задаёт максимум в 900 измерений. Если сборка завершится раньше, фоновый сбор данных продолжится. Скрипт проекта может после завершения сборки отправить процессу сбора сигнал TERM, но необходимо сохранить корректную обработку завершения, чтобы в CI не оставались запущенные процессы. Если использовать powermetrics невозможно, сохраните как минимум вывод pmset -g therm, time -lp и снимок процессов, отсортированных по загрузке CPU.
Вывод о тепловом троттлинге должен одновременно подтверждаться динамикой времени выполнения и системными сигналами. Одного эпизода высокой загрузки CPU для такого вывода недостаточно.
Делайте выводы по кривой, а не по отдельной точке
Сведите в одну таблицу фактическое время каждого прогона, максимальный объём резидентной памяти, тепловое давление и процессы с высокой нагрузкой за тот же период. Если первый прогон медленный, а следующие заметно ускоряются, причиной обычно служит прогрев кэша. Если внезапно замедляется только один прогон и одновременно выполняется загрузка зависимостей или индексирование, вероятнее всего, ресурсы используются конкурирующими процессами.
Особого внимания заслуживает следующая картина: код и состояние кэша не меняются, но время нескольких последовательных прогонов постепенно растёт; CPU долго работает под полной нагрузкой; одновременно усиливаются сигналы теплового давления; после остановки нагрузки и периода простоя следующий прогон возвращается к обычной скорости. Тепловой троттлинг следует считать основной причиной только при одновременном наличии всех этих признаков.
Исключите три распространённых ложных срабатывания
Сначала проверьте, не запускает ли сборка незаметно тесты, архивацию или скрипты загрузки. Затем сравните количество компилируемых файлов в журналах и убедитесь, что объём работы одинаков во всех прогонах. Наконец, проверьте, не работают ли параллельно несколько процессов xcodebuild, симуляторы или менеджеры пакетов. Во время аномального прогона можно сохранить:
date -u
pgrep -alf 'xcodebuild|swift-frontend|clang|Simulator'
top -l 3 -o cpu -stats pid,command,cpu,mem,time
du -sh "$RUN_ROOT/DerivedData"
Моментальный рейтинг top показывает только то, какие процессы потребляли ресурсы в момент измерения, и сам по себе не доказывает первопричину. Связать состояние системы с нагрузкой проекта позволяют количество задач и продолжительность их выполнения в журнале сборки.
Определите условие срабатывания с помощью контролируемых экспериментов
После подтверждения тенденции изменяйте только одну переменную за раз. Сначала уменьшите число параллельных заданий CI до 1, оставив остальные условия без изменений. Затем восстановите параллельное выполнение, но разнесите время запуска заданий. В завершение сравните холодные и тёплые сборки. Если после снижения параллелизма кривая времени стабилизируется, причина, скорее всего, заключается в конкуренции задач на одном узле или в слишком высоком длительном энергопотреблении, а не в деградации самого компилятора.
Не пытайтесь сразу устранить проблему более агрессивной очисткой кэша. Очистка увеличит объём работы следующего прогона и скроет исходную тенденцию. Перезагрузка также не должна быть единственным доказательством: она одновременно завершает фоновые процессы, сбрасывает часть состояния и даёт машине время остыть, поэтому невозможно определить, какое именно изменение помогло.
Настройте расписание сборок вместо погони за мгновенной частотой
Надёжное решение обычно состоит в ограничении числа тяжёлых задач на одном узле, разнесении по времени архивации, полного набора тестов и статического анализа, а также в выделении отдельного каталога DerivedData каждому конвейеру. Если задачи обязательно должны выполняться параллельно, сначала измерьте медианное время при уровнях параллелизма 1, 2 и 3, а затем выберите вариант с максимальной общей пропускной способностью, а не с наибольшей пиковой производительностью одной задачи.
Закрепите результаты диагностики как базовый уровень CI
Базовый уровень должен включать команду, коммит, версию Xcode, тип сборки, количество последовательных прогонов и медианное время. Не используйте самый быстрый прогон в качестве эталона и не блокируйте слияние из-за единственного превышения времени. Более надёжное правило — сравнивать скользящие медианы нескольких последних прогонов и создавать диагностическую запись только после нескольких последовательных превышений порога.
Итоговые материалы должны включать как минимум журнал сборки, вывод time, данные о тепловом давлении, снимки процессов и параметры сбора метрик. Если проблему нужно передать на следующий уровень поддержки, приложите регион узла, время возникновения, шаги воспроизведения и минимально необходимые журналы, но не отправляйте пароли, закрытые ключи или полные учётные данные. Тогда при повторном появлении похожих колебаний команда сможет сразу запустить тот же набор измерений, а не начинать диагностику с новых предположений.
Часто задаваемые вопросы
Можно ли считать один медленный запуск Xcode признаком троттлинга?
Нет. Нужно зафиксировать версию кода и Xcode, состояние кэша и параллелизм, затем сравнить минимум три запуска с показателями мощности, теплового давления и фоновой нагрузки.
Нужны ли powermetrics права администратора?
Обычно нужны. Безопаснее разрешить через sudo только команду с ограниченным набором параметров и сохранять результат в контролируемый каталог.
Перенесите задачи сборки на выделенный облачный Mac
Выберите VMOrbit M4 или VMOrbit M4 Pro и узел с учётом расположения команды. Фактическая доступность и сведения о выдаче отображаются в консоли в реальном времени.