Команды мобильного CI на Mac mini M4 часто повышают параллелизм xcodebuild, потому что графики CPU кажутся пустыми—а затем удивляются росту p95 очереди, хотя каждый процесс сообщает «всего» около сорока процентов. Эта матрица 2026 разделяет полосы, упирающиеся в компиляцию, и полосы симулятора и IO, показывает, как выбор -destination конфликтует в унифицированной памяти, и даёт девять шагов внедрения с числовыми ограничителями для YAML оркестратора.
Читайте вместе с дросселями параллельных воркеров симулятора и памяти и шардированием UI-тестов на Mac mini M4, чтобы не крутить три «ручки параллелизма», борющиеся за один бюджет DRAM. Если артефакты на диске растут быстрее самой параллельности, сверьтесь с матрицей удержания диска прежде чем винить Xcode.
Почему процент CPU лжёт на Apple Silicon CI
Унифицированная память означает, что GPU, Neural Engine и контроллеры CPU делят один физический пул. Полоса, тратящая время на композицию framebuffer CoreSimulator или подготовку пайплайнов Metal, может показывать скромный CPU и всё равно голодать соседние задачи, которым нужна пропускная способность для компиляции модулей Swift. Copy-on-write APFS усиливает иллюзию: удаление и пересоздание наборов данных симулятора взрывает трафик метаданных, не двигая кривые «CPU занят».
- Общие кэши CoreServices: несколько destination бьют в одни и те же вспомогательные демоны и защищённые кэши.
- Штормы загрузки: четыре симулятора параллельно выглядят нормально, пока watchdog SpringBoard тихо не перезапустит одну полосу.
- Конкуренция Metal: снимки UI и лёгкие GPU-тесты всё равно спорят с кэшированием шейдеров компиляции на том же срезе GPU.
Правило оператора: если два destination делят семейство udid и один срез DerivedData, это не изоляция—это гонка.
Матрица A — тип полосы и безопасный параллелизм на уровнях M4
| Тип полосы | Уровень 24 ГБ | Уровень 36–48 ГБ | Заметки |
|---|---|---|---|
| Только компиляция Swift | 2 тяжёлые | 3 тяжёлые | Корни DerivedData на задачу; следите за всплесками памяти фронтенда компилятора. |
| Юнит-тесты (без UI) | 2 | 3 | Симуляторы всё равно выделяются—не «бесплатно» относительно чистой компиляции. |
| XCUITest + скриншоты | 1 | 2 | Доминируют GPU и диск; для масштабирования флота следуйте гайду по шардированию. |
Матрица B — симптом, вероятное узкое место, первая мера
| Симптом | Узкое место | Смягчение |
|---|---|---|
Случайные обрывы DTXProxy |
IPC симулятора + давление памяти | Снизить параллельные UI-полосы; добавить хуки остановки между наборами. |
| Компиляция замедляется при параллельных UI-задачах | Пропускная способность унифицированной памяти | Разделить пулы компиляции и UI метками; планировать UI вне пика. |
| ~60 % свободно, но билды ползут | Фрагментация APFS / скачки inode | Еженедельно ротировать локальные тома задач; избегать одного гигантского общего DerivedData. |
Числовые ограничители для оркестраторов
- Потолок UI на хост: на машинах с 24 ГБ унифицированной памяти держите одновременные XCUITest destination на 1, если профилирование не показывает минимум 6 ГБ возвращаемого запаса после загрузки.
- Веер компиляции: при смешивании с симуляторами ограничьте воркеры
-parallel-testing-enabledполовиной физических производительных ядер. - Водяной знак диска: приостанавливайте новые параллельные destination, когда свободное место APFS на CI-томах падает ниже 18 %—ниже создание CoreSimulator часто падает непрозрачно.
Связь с ёмкостью: если матрицы показывают, что одного хоста мало, сопоставьте параллелизм с SLO ёмкости пула прежде чем просто покупать большие диски.
Паттерны вызова, проходящие ревью кода
Относитесь к аргументам xcodebuild как к контракту API: оборачивайте их в небольшие shell-функции или YAML-якоря, чтобы каждая полоса стабильно задавала -derivedDataPath, -clonedSourcePackagesDirPath и -resultBundlePath. Разовые команды в CI «чтобы разблокировать» лишают вас корреляции регрессий насыщения и дрейфа конфигурации. Явные блоки -destination в репозитории лучше shell-глобов, которые по-разному раскрываются в пятницу вечером и в понедельник утром.
Матричные билды шардируйте по классу теста или таргету—не только по имени destination—чтобы каждый шард нёс предсказуемые сигнатуры GPU/IO. Сопоставьте манифесты шардов с политикой загрузки артефактов, чтобы упавшие шарды успели опубликовать xcresult до агрессивной очистки. Логируйте число эффективных производительных ядер и тепловое состояние, если оркестратор это отдаёт; macOS может тихо троттлить под длительной параллельной UI-нагрузкой.
Централизованные кэши: ускоритель или IO-бомба
Общий DerivedData или кэши SwiftPM сильно сокращают холодные билды, но десятки задач, бьющие в одно дерево, сериализуют записи метаданных. Централизуя, выносите на быстрые APFS-тома с запасом inode и принудительными подпапками на задачу, чтобы штормы блокировок не расползались между командами. Сочетайте попадания в кэш с явной политикой вытеснения—устаревшие module map хуже промахов: падают загадочно до ручной очистки.
Если кэш на сетевом хранилище, всплески задержек маскируются под «flaky» симуляторы; для горячих путей предпочитайте локальный NVMe и асинхронно реплицируйте артефакты. Документируйте, какие полосы могут читать/писать общий кэш против зеркал только для чтения, чтобы security-ревью оставалось прослеживаемым.
Девять шагов внедрения для владельцев платформы сборки
- Метки полос: компиляция, юнит или UI в метаданных оркестратора—человекочитаемые лучше магических чисел.
- Закрепляйте destination: явные UDID симуляторов в CI, не только «последний iPhone».
- Измеряйте время на стене по типу полосы еженедельно; регрессии приходят раньше красных билдов.
- Изолируйте DerivedData по ID полосы; запретите неявное разделение между матричными задачами.
- Ограничивайте Metal, когда UI-тесты пишут видео; при необходимости сериализуйте.
- Автоостановка симулятора после каждого шарда; каденция стирания по гайду дросселя.
- Алерты по задержке IO через прокси (дисперсия длительности шага), если нет счётчиков ядра.
- Документируйте эскалацию на VNC при TCC посреди набора.
- Географическое масштабирование по Гонконгу, Японии, Корее, Сингапуру и США прежде чем складывать несовместимые полосы на одном «геройском» раннере.
FAQ
Помогает ли xcodebuild -parallelizeTargets в CI?
Иногда для мультитаргетных приложений, но наращивает фронтенды компилятора—измеряйте до глобального включения на общих хостах.
Стоит ли фиксировать старые рантаймы симулятора ради стабильности?
Для воспроизводимости да, но отслеживайте даты окончания поддержки Apple; документируйте окна обновления вместе с пинами Xcode.
Где читать про SSH и VNC для удалённых Mac?
Начните со справочного центра; для интерактивных проблем симулятора используйте VNC.
Правильно подобрать параллельные destination xcodebuild — значит держать CI на Apple Silicon M4 честным: чип быстрый, но унифицированная память и метаданные APFS превращают наивный параллелизм в скрытые очереди. Нативный macOS с автоматизацией прежде всего по SSH и опциональным VNC для зависших подсказок симулятора соответствует серьёзным мобильным удалённым лабораториям. Аренда выделенных Mac mini M4 в Гонконге, Японии, Корее, Сингапуре и США позволяет разделить тяжёлую компиляцию и тяжёлый UI без CapEx, а физическая изоляция лучше, чем складывать несовместимые destination на один диск. При конкуренции откройте цены и добавьте хосты вместо слепого кручения ручек параллелизма.