Параллельная сборка
Параллельная сборка#
Программа вместе с достижимой частью std — один модуль LLVM. После оптимизации (она идёт в одном потоке) модуль режется на
кодогенерационные единицы (codegen units): каждая единица компилируется в свой объектный файл в отдельном потоке, затем все
объекты передаются компоновщику. Это действует во всех командах, которые собирают программу: oxl build, oxl run, oxl test.
Единицы и потоки — это разные вещи#
| Что | Флаг | Окружение | oxl.toml | Влияет на результат |
|---|---|---|---|---|
| Число единиц | --codegen-units N (1..256) | OXL_CODEGEN_UNITS | [profile.<имя>] codegen-units = N | да |
| Число потоков | -j N / --jobs N | OXL_JOBS | — | нет |
| Компоновщик | --linker auto|lld|bfd|gold|default|<путь> | OXL_LD | — | да (другой файл) |
Приоритет: флаг, затем окружение, затем oxl.toml, затем автоматический выбор.
- Воспроизводимость. Бинарный файл зависит только от числа единиц, но не от
-j, числа ядер и порядка выполнения потоков: модуль режется и сериализуется в фиксированном порядке, параллельна только кодогенерация уже готовых частей, объекты передаются компоновщику в порядке единиц. Сборки-j1и-j8с одинаковыми единицами побайтно совпадают (см. D-1403, D-9001). - Автоматический выбор. Без явного числа единиц оно зависит только от содержимого модуля: одна единица на каждые ~5000
инструкций после оптимизации, не больше 8. Малая программа (например,
examples/hello) собирается в одну единицу, как раньше. Число ядер на выбор не влияет, поэтому на любой машине получается один и тот же файл. - Локальные символы модуля при разрезании становятся внешними с видимостью
hidden; наружу из исполняемого файла они не попадают. - Профиль с
lto = trueи--emit-llvmне режутся: LTO остаётся одним модулем (объект — биткод, оптимизацию делает lld). - macOS: единица одна (карта отладки Mach-O и воспроизводимый UUID требуют одного объекта), флаги принимаются и игнорируются.
- Цена: отладочная информация и метаданные дублируются между частями, бинарник чуть больше (см. «Параллельная сборка» в
бенчмарках). Для самого быстрого и самого маленького бинарника:
--codegen-units 1.
Компоновщик#
Если в PATH есть ld.lld (или ld.lld-18), oxl компонует с -fuse-ld=lld: ссылка занимает ~50 мс вместо ~160 мс у GNU ld.
Без lld всё работает как раньше (молча используется компоновщик драйвера). Если автоматически выбранный lld не справился
с ссылкой, она повторяется стандартным компоновщиком. --linker bfd (или OXL_LD=bfd) принудительно выбирает GNU ld,
--linker default не передаёт -fuse-ld вовсе, --linker /путь/к/ld — свой компоновщик. oxl doctor показывает, что выбрано.
Компоновщик входит в ключ кэша сборки.
Кэш сборки#
В ключ локального кэша сборки (OXL_BUILD_CACHE=1, D-6313) входят число единиц и компоновщик, но не число потоков.
Тесты#
oxl test принимает --codegen-units N и --linker; потоки сборки берутся из OXL_JOBS (флаг -j у oxl test — число
одновременно идущих тестов). Пакеты рабочего пространства собираются по одному, каждая сборка сама параллельна внутри.