Узкие места в сборке ядра Linux искала языковая модель, и она же написала первую версию исправлений – много кода, значительную часть которого автор набора назвал ужасной. Инженер ARM отправил получившиеся 23 патча в рассылку , предварительно переписав заметную долю сгенерированного, отредактировав сообщения коммитов и проверив результат вручную. По его замерам полная сборка allmodconfig ускоряется до 36%, инкрементальная – примерно до 70%, а повторный запуск make без правок – примерно до 90%. Правки затронули kbuild, kallsyms, modpost, objtool, mksysmap и сборку Rust-кода: 47 файлов, 2884 добавленные строки против 682 удалённых.
Что делала языковая модель и что за ней переписали
Сопроводительное письмо описывает участие модели прямым текстом, без обтекаемых формулировок. Она сначала выясняла, где именно сборка упирается в один поток, затем предлагала способы это исправить, а дальше запускала сборки, тестирование, отладку и анализ результатов. Код при этом получился далеко не готовым к отправке.
Языковая модель сначала определила, где находятся узкие места, а затем нашла способ их устранить. Она сгенерировала много кода, значительная часть которого ужасна.
– из сопроводительного письма к набору патчей
Дальше работал человек: по собственному описанию, автор подробно проверил и во многом переписал сгенерированное, отредактировал сообщения коммитов, сопроводительное письмо и комментарии, а корректность собранных и запущенных ядер, как и прирост производительности, подтверждал вручную. Ценность модели свелась не к написанию кода, а к поиску мест, где однопоточные этапы съедают время сборки.
Где сборка ядра упиралась в один поток
Заметная доля времени при сборке ядра уходит на этапы, выполняемые в одном потоке, пока остальные ядра процессора простаивают. В наборе такие этапы распараллелены, а объём работы внутри них сокращён – от подготовки таблицы символов до финальной сборки модулей.
allmodconfig – конфигурация, в которой как можно больше компонентов ядра включено модулями; в документации ядра она описана как установка значения «m» для максимального числа параметров.
Изменения по подсистемам выглядят так:
- mksysmap переписан на C, а kallsyms читает таблицу символов ELF напрямую вместо запуска nm и не сортирует его вывод там, где порядок не важен;
- kbuild хранит в кеше состояние объектов, сверяет метки времени зависимостей отдельной утилитой depcheck и опрашивает флаги компилятора и компоновщика один раз в начале сборки;
- modpost хеширует исходники модулей по файлам, а не по байтам, и вычисляет srcversion параллельно в пуле потоков;
- дескрипторы модулей выводятся ассемблерным кодом (*.mod.S) вместо C, что, согласно сопроводительному письму, сокращает процессорное время на этой операции в десять раз;
- objtool больше не засоряет хеш-таблицу миллионами DWARF-записей о перемещениях и декодирует крупные объекты в несколько потоков;
- код на Rust собирается параллельно с C-кодом, распараллелена и начальная стадия компиляции в rustc;
- для сжатия по умолчанию берётся pigz, если он установлен в системе.
pigz – параллельная реализация gzip; последний патч набора включает её вместо обычного gzip, когда утилита доступна на сборочной машине.
Замеры на Threadripper, EPYC и MacBook Pro M2
Автор приводит результаты трёх стендов: 64-ядерный Threadripper 9980X со 128 потоками, двухпроцессорная система на EPYC 9754 с 256 ядрами и 512 потоками, а также MacBook Pro 2022 года на M2 с восемью ядрами, из которых четыре производительных. Время сборки взято как лучший результат из нескольких прогонов.
| Стенд | Компилятор | До | После | Изменение |
|---|---|---|---|---|
| Threadripper 9980X | gcc | 345,3 с | 275,2 с | -20% |
| Threadripper 9980X | clang | 345,5 с | 265,7 с | -23% |
| EPYC 9754, два сокета | gcc | 188,6 с | 121,1 с | -36% |
| EPYC 9754, два сокета | clang | 261,7 с | 184,6 с | -29% |
Верхняя граница в 36%, вынесенная в описание набора, получена на EPYC с gcc. Сборка той же конфигурации на Threadripper выигрывает 20% с gcc и 23% с clang, то есть около 70–80 секунд на каждый полный прогон. Для defconfig на MacBook Pro сокращение оказалось наименьшим среди всех стендов – 9% с gcc и 8% с clang.
Инкрементальная сборка и повторный make без изменений
Самый крупный выигрыш приходится не на полную пересборку, а на повторные запуски. Инкрементальная сборка allmodconfig на EPYC с gcc сократилась с 82 до 24,3 секунды, на Threadripper – с 46,4 до 15,3 секунды; в процентах это 70% и 67% соответственно. Для defconfig разброс составил от 47% на MacBook Pro до 57% на Threadripper с clang.
Сборка без изменений – повторный запуск make сразу после успешной сборки, когда исходный код не менялся: система сборки только сверяет зависимости и метки времени, ничего не компилируя.
Именно здесь разница максимальна. На EPYC с gcc холостой прогон занимает 1,52 секунды вместо 25,92, на Threadripper – 1,18 секунды вместо 12,97, что соответствует 94% и 91%. В сопроводительном письме верхняя граница указана осторожнее, как «примерно 90%». Для defconfig на MacBook Pro холостой прогон сжался с 5,59 до 1,69 секунды.
Ошибка mksysmap: лишние символы в kallsyms с версии 6.18
В наборе есть и исправление, найденное по ходу разбора сборки. Регулярное выражение в scripts/mksysmap отсеивало служебные символы MODULE_INFO() из System.map и kallsyms, рассчитывая на имена вида __UNIQUE_ID_modinfo123, но в том же цикле разработки формат сменился на __UNIQUE_ID_modinfo_123, и выражение перестало совпадать.
Как сказано в описании патча, каждое ядро начиная с 6.18 несёт по записи kallsyms на каждое объявление MODULE_INFO() независимо от того, собираются ли соответствующие модули: 5810 записей для x86 defconfig и 15 200 для arm64. На x86 это 113 КиБ таблиц kallsyms и 32 КиБ образа bzImage, а каждый поиск символа проходит мимо этих записей. На время сборки исправление при этом не влияет.
Тег Assisted-by: LLM и правила ядра для ИИ-кода
Каждый коммит набора помечен тегом Assisted-by: LLM. Имя модели не названо, и правилам ядра это не противоречит: документация по ИИ-ассистентам задаёт именно формат Assisted-by: LLM с необязательным перечислением инструментов анализа вроде coccinelle или sparse.
Там же зафиксировано главное ограничение: тег Signed-off-by ИИ-агент ставить не может, поскольку удостоверить сертификат происхождения кода вправе только человек. За проверку, лицензионную чистоту и последствия отвечает тот, кто отправил патч, и в этом наборе такая проверка описана отдельным абзацем сопроводительного письма.
Кому пригодится ускорение сборки
Сильнее всего экономия чувствуется при ежедневной работе над кодом ядра, когда после правки одного файла запускается инкрементальная сборка: на 64-ядерной машине она укладывается в 15 секунд вместо 46, а холостая проверка дерева исходников – в секунду с небольшим вместо тринадцати.
Полная сборка ближе к сценарию сопровождающих пакетов: ядро для Fedora Workstation и других дистрибутивов собирается целиком, и минута с небольшим, снятая с каждого прогона, складывается в заметное время на сборочных серверах.
Отдельный случай – дистрибутивы с собственными вариантами ядра. CachyOS поставляет ядро linux-cachyos с планировщиком BORE и предлагает альтернативные сборки с EEVDF, sched-ext, ECHO и RT, а каждая из них проходит полный цикл компиляции.
Набор ещё не прошёл рецензирование
Происхождение кода не даёт набору поблажек: правила рецензирования для него те же, что и для любого другого патча. В ветке рассылки на момент подготовки материала есть один ответ: идею поддержали, заметив, что при 128 ядрах значительная часть сборки идёт последовательно, но код при этом не рецензировали.
Заявленная проверка охватывает не только x86: allmodconfig собирали для arm64, arm, riscv, powerpc64, s390 и loongarch, причём для arm64, arm, s390 и loongarch System.map совпал с результатом прежней реализации mksysmap. Ядра для девяти архитектур загружаются в qemu, модуль подгружается и выгружается, а на s390, arm и loongarch проходит самотестирование kallsyms. Патчи опубликованы во время цикла 7.3-rc, в какой релиз попадут изменения, пока не определено.
Заключение
История показательна не объёмом сгенерированного кода, а разделением ролей: модель нашла узкие места, которые годами никто не разбирал, а пригодный к отправке вид патчам придал человек. Результат измеряется секундами на каждом запуске make: 1,52 вместо 25,92 на холостом прогоне, 24,3 вместо 82 на инкрементальном и до 36% на полной сборке allmodconfig. Пока изменения только опубликованы в рассылке, оценить их можно самостоятельно, применив набор из 23 патчей к своему дереву исходников.