Сборка ядра Linux 5.12.11 c LLVM 12 + Clang и LTO оптимизацией +58


AliExpress RU&CIS


Технический прогресс не стоит на месте, появляются новые компьютерные архитектуры, компиляторы становятся умнее и генерируют более быстрый машинный код. Современные задачи требуют все более креативного и эффективного решения. В данной статье пойдет речь, на мой взгляд, про один из самых прогрессивных тулчейнов LLVM и компиляторы на его основе Clang и Clang++, для языков программирования С и C++ соответственно. Хоть GCC — конкурент Clang, может агрессивнее оптимизировать циклы и рекурсию, Clang дает на выходе более корректный машинный код, и чаще всего не ломает поведение приложений. Плюс оптимизация программ не заканчивается только оптимизацией циклов, поэтому Clang местами дает лучшую производительность. В GCC же за счет переоптимизации вероятность получить unpredictable behavior значительно выше. По этой причине на многих ресурсах не рекомендуют использовать -O3 и LTO(Link Time Optimization) оптимизации для сборки программ. Плюс в случае агрессивной оптимизации, размер исполняемых файлов может сильно увеличиться и программы на практике будут работать даже медленнее. Поэтому мы остановились на Clang не просто так и опции компиляции -O3 и LTO работают в нем более корректно. Плюс современные компиляторы более зрелые, и сейчас уже нет тех детских болячек переоптимизации и LTO.

Что меня побудило написать эту статью? — В первую очередь это несколько фактов:

  1. Впервые прочел про сборку ядра Linux с LTO оптимизацией и Clang из новостей, где упоминалась компания Google. Она использует Clang и LTO оптимизацию для сборки ядра Linux и получения лучшей производительности. Компания Google для меня является синонимом инноваций, лучших программистов в мире и поэтому для меня ее опыт является самым авторитетным. Плюс она привнесла очень много в развитие open source, и ее наработками пользуются тысячи компаний во всем мире.
  2. Хоть компания Google начала использовать Clang и LTO оптимизацию раньше, только с выходом ядра Linux 5.12.6 и 5.12.7 было закрыто большое количество багов, и сборка ядра c LTO оптимизаций стала доступна многим. До этого при сборке ядра с LTO оптимизацией многие драйвера давали сбой.
  3. Мною уже протестирована работа ядра с LTO на Ryzen 9 3900x + AMD Radeon 5700 XT. Плюс уже давно использую LLVM 12 и Clang для сборки системных программ. Инструментарий LLVM12 и Clang стали основными в моей системе по причине лучшей поддержки моего процессора и нужные мне программы работают быстрее при сборке с помощью Clang. Для программистов Clang дает лучший контроль ошибок, оптимизации и unpredictable behavior. -fdebug-macro, -fsanitize=address, -fsanitize=memory, -fsanitize=undefined, -fsanitize=thread, -fsanitize=cfi, -fstack-protector, -fstack-protector-strong, -fstack-protector-all, -Rpass=inline, -Rpass=unroll, -Rpass=loop-vectorize, -Rpass-missed=loop-vectorize, -Rpass-analysis=loop-vectorize и т.д.
  4. Данная возможность толком нигде не была описана в связи с п.2 и есть подводные моменты, которые будут рассмотрены в данной статье.

В этой статье будет описана сборка ядра Linux 5.12.11 c LLVM 12 + Clang и LTO оптимизацией. Но так как статья получилась бы короткой, то так же бонусом будет рассмотрен вопрос как сделать утилиты LLVM 12 и Clang сборочным инструментарием по умолчанию, и какие программы и библиотеки имеет смысл собрать вручную, чтобы получить лучший отклик и производительность от системы. GCC имеет более лояльную лицензию на использование, и поэтому он установлен во многих дистрибутивах по умолчанию.

Так как в новом ядре фиксится немалое количество багов для работы с моим оборудованием(Ryzen 9 3900x + AMD Radeon 5700 XT) будет рассмотрен вопрос автоматизации сборки и установки нового ядра, чтобы это сильно не отвлекало и занимало минимум времени. Думаю многим это будет полезно. Будет рассмотрен принцип работы моего сборочного скрипта. Все действия будут проводиться в Arch Linux. Если статья будет хорошо оценена, то она станет вводной частью в серию статей про оптимизацию Linux, где будут рассмотрены внутренние механизмы ОС, и как оптимизировать их работу, будут рассмотрены вредные советы и ошибки оптимизации, и будет дан ответ на вопрос оптимизации системы «Что для русского хорошо, то для немца смерть!».

Хоть тема оптимизации описывалась многократно, не мало где дают вредные советы, и некоторые механизмы ОС описаны с ошибками. Чаще всего это происходит из-за сложностей перевода или минимальной документации в интернете к компонентам ядра Linux. Где-то информация вовсе устарела. Плюс некоторые вещи понимают программисты, но не понимают системные администраторы, и наоборот. Изначально после установки Linux работает относительно медленно, но благодаря оптимизации и гибкой настройке, можно добиться более высокой производительности и значительно улучшить отклик системы. Arch Linux у меня используется как основная система, и отклик системы, производительность лучше, чем в Windows 10.
Внимание, автор статьи не несет ответственность за причиненный вред в следствии использования данной статьи! Все действия вы выполняете на свой страх и риск! Все действия должны выполнять только профессионалы!

?Немного теории


LTO или Link Time Optimization это оптимизация на этапе линковки(компоновки). Чтобы понять, что такое LTO рассмотрим как работают компиляторы. В большинстве компиляторов используется двух этапная модель: этап компиляции и этап линковки.

На этапе компиляции:

— Парсятся исходные тексты программ, строится ASTАбстрактное Синтаксическое Дерево.

  • Оптимизируется Абстрактное Синтаксическое Дерево. Оптимизируются циклы, удаляется мертвый код, результат которого нигде не используется. Раскрываются выражения, например 2+5 можно заменить на 7, чтобы при работе приложения не вычислять его значение каждый раз и тем самым сделать его быстрее и т.д.
  • Оптимизированное дерево может быть преобразовано в машинный псевдокод понятный компилятору. Псевдокод используется для дополнительной оптимизации, упрощает разработку универсального компилятора для разных архитектур процессора, например для x86-64 и ARMv7. Так же как ASM листинг, этот псевдокод еще используется, чтобы понять, как компилятор генерирует машинный код, и служит для понимания работы компилятора, поиска ошибок, например, ошибок оптимизации и unpredictable behavior. Стоит заметить этот этап не является обязательным и в некоторых компиляторах отсутствует.
  • Происходит векторизация. Векторизация ,Automatic Vectorization, SIMD
  • Генерируется объектный файл. Объектный файл содержит в себе машинный код для компьютера, и специальные служебные структуры, в которых все еще есть неизвестные адреса функций и данных, поэтому этот файл все еще не может быть запущен на исполнение. Чтобы разрешить неизвестные адреса, был добавлен этап линковки.

Компьютер работает только с бинарными данными, и может оперировать только адресам, поэтому имя функции и переменной ему ничего не говорят. Имя это лишь формальность для программистов, чтобы удобнее было читать исходный код. Во многих компилируемых языках программирования невозможно вычислить адрес функций на этапе компиляции, поэтому в них был придуман механизм описания функций.

Если мы используем функцию и она реализована в каком-то другом файле, то мы должны описать ее имя, параметры и возвращаемое значение. Тем самым мы скажем компилятору, что не надо искать ее в этом файле и она будет добавлена на этапе линковки. Так же, это упрощает парсинг исходных файлов. Нам больше не надо для компиляции и разрешения адресов читать все файлы за один раз. Представьте себе, что у вас исходный код программы занимает несколько гигабайт, такой размер нередко встречается в серьезных программах, тогда оперативной памяти большинства компьютеров не хватило бы, чтобы хранить все служебные структуры компилятора, что значительно повысило бы стоимость разработки и самих программ.

На этапе линковки:

  • Происходит подстановка адресов
  • Добавляются дополнительных данных для работы программы, например ресурсы
  • Происходит сборка всех объектных файлов в конечный исполняемый файл или распространяемую библиотеку, которая может быть использована в других программах

Понимая это мы можем понять, что LTO оптимизация это дополнительная оптимизация исполняемых файлов, которая не может быть произведена на этапе компиляции и происходит на этапе линковки.

В Clang используется два вида LTO Оптимизации: Full LTO и Thin LTO. Full LTO — это классическая реализация LTO оптимизации, которая обрабатывает конечный исполняемый файл за раз целиком и использует много оперативной памяти. Отсюда эта оптимизация занимает много времени, но дает на выходе самый быстрый код. Thin LTO — это развитие LTO оптимизации, в которой нет оптимизации всего файла целиком, а вместо этого вместе с объектными файлами записывают дополнительные метаданные, и LTO оптимизатор работает с этими данными, что дает более высокую скорость получения оптимизированного исполняемого файла (скорость сравнима с линковкой файла без LTO оптимизации) и код сравнимый или чуть уступающий в производительности Full LTO. Но самое главное Full LTO может значительно увеличить размер файла, и код наоборот может из-за этого работать медленнее. Thin LTO лишен этого недостатка и в некоторых приложениях на практике мы можем получить лучшую производительность! Поэтому наш выбор будет сборка ядра Linux с Thin LTO.

Дополнительная информация:


?Установка LLVM 12 и Clang


Поставить llvm и clang можно выполнив в консоли под root команду:

pacman -Syu base-devel llvm clang lld vim

Это самый простой вариант установки, но лично предпочитаю новые версии ПО, и git версия закрыла часть багов компилятора и даже стабильнее релиза. Так как за время написания статьи многое поменялось, вышел официальный пакет llvm 12, то чтобы понять ход мыслей, рекомендуется к прочтению прошлая версия по установке.

Прошлая версия
На момент написания статьи, в дистрибутиве Arch Linux используются LLVM и Clang версии 11. А LLVM и Clang версии 12 находятся в staging репозитории Arch Linux [LLVM](https://archlinux.org/packages/staging/x86_64/llvm/). Staging репозиторий это репозиторий, где находятся версии пакетов, которые ломают приложения, зависящие от прошлой версии. Он используется для компиляции всех зависящих программ, и когда все они будут собраны, все пакеты за раз переходит в общий репозиторий. Например, в Arch Linux от LLVM и Clang версии 11 зависят blender, rust и qt creator и т.д. Если мы поставим LLVM и Clang версии 12, то они перестанут работать.
Upd. Пакет уже перешел в основной репозиторий. Так как мною одним из первых была произведена миграция на LLVM и Clang 12, то было придумано простое решение, создать пакет [llvm11-libs](https://aur.archlinux.org/packages/llvm11-libs-bin/) с необходимыми библиотеками для обратной совместимости, который позволяет оставить зависимые программы рабочими. Но данный пакет работает только с моим сборочным пакетом [llvm12-git](https://aur.archlinux.org/packages/llvm12-git/). Поэтому мы будем собирать LLVM и Clang 12 из исходников. Но вы можете дождаться, когда LLVM и Clang 12 появятся в основном репозитории Arch Linux или использовать 11 версию. Лично предпочитают новые версии ПО, и LLVM и Clang 12 лучше поддерживают мой процессор Ryzen 9 3900X. Плюс git версия закрыла часть багов компилятора и даже стабильнее релиза. Релизный архив с официального сайта у меня не проходит больше тестов при сборке чем git версия. Не стоит пугаться того, что часть тестов компилятор провалил, там нет критических багов для x84-64 архитектуры, и большая часть затрагивают другие компоненты, например openmp и lldb. За очень долгое время тестирования llvm и clang 12 мною не было замечено ни одного бага влияющего на работу системы. Стоит заметить, на данный момент 13 версия является очень сырой и нам не подходит!

Поставим llvm и clang 11 версии(Если 12 версия появилась в основном репозитории, то поставится 12я версия) можно выполнив в консоли под root команду:

pacman -Syu base-devel llvm clang lld libclc vim

Обновить Arch Linux и поставить новые версии программ можно командой(это будет полезно тем кто будет ждать официального выхода 12 версии, думаю это произойдет уже через пару дней):

pacman -Syu

Кто остановился на этом варианте можно пропустить следующий пункт. Для остальных, будет дана инструкция по установке моего пакета.

Cборка LLVM 12 из Arch User Repository


Для сборки нам понадобиться git и нам надо будет собрать программу yay.

Поставим необходимые зависимости, для этого нам будут нужны права root: pacman -Syu base-devel git go vim

Если вы хотите собрать llvm 12 с помощью clang 11, то надо поставить еще их: pacman -S llvm clang lld

Отредактируем конфигурационный файл сборщика пакетов makepkg в Arch Linux и увеличим количество потоков для сборки программ. Это ускорит скорость сборки. Под root выполним: vim /etc/makepkg.conf

Найдем строки MAKEFLAGS и NINJAFLAGS. Нажмем латинскую букву A. Нам после -j надо указать количество потоков для сборки. Рекомендуется ставить ваше количество ядер или потоков процессора, если ядер 4, то ставим 4 или 8. У меня это 20, 12 ядер — 24 потока, 4 остаются запасными для других задач. Или используем автоматическое определение $(nproc).

В итоге получим:

MAKEFLAGS="-j20"
NINJAFLAGS="-j20"

или

MAKEFLAGS="-j$(nproc)"
NINJAFLAGS="-j$(nproc)"

Нажмем ESC, дальше SHIFT + :(буква Ж). Внизу появится : — строка для ввода команд, вводим wq. w — write, записать изменения в файл. q — quit, выйти из vim. q! выход из vim без сохранения файла. Кому сложно разобраться с vim, в Linux есть замечательная программа, называется она vimtutor. Если у вас настроена правильно локаль, то vimtutor будет на русском, запустить его можно командой vimtutor. Стоит заметить, вопреки распространенному мнению, обучение у вас не займет много времени. Обычно новичков пугают мифом: vi и vim люди изучают очень долго, и осилить их могут только единицы. На самом деле это не так и там нет ничего сложного.

Под обычным пользователем клонируем репозиторий yay, собираем и устанавливаем:

git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -cfi

Импортирует открытый gpg ключ, он необходим для проверки подписи llvm12-git:

gpg --keyserver pgp.mit.edu --recv-keys 33ED753E14757D79FA17E57DC4C1F715B2B66B95

Поставим LLVM 12 и библиотеки совместимости с 11 версией. Стоит заметить, мой пакет LLVM 12 уже содержит все необходимые утилиты, включая Clang и LLD и их не надо ставить отдельно.
Под обычным пользователем выполним команду:
pacman -Syu base-devel llvm clang lld vim git   ninja cmake libffi libedit ncurses libxml2
  ocaml ocaml-ctypes ocaml-findlib python-setuptools   python-psutil python-sphinx python-recommonmark


Затем
git clone https://github.com/h0tc0d3/llvm-git.git && cd llvm-git && makepkg -cfi


Команда yay задаст вам несколько вопросов, нажмите Enter в ответ на все. Сборщик LLVM задаст 3 вопроса:

  • Build with clang and llvm toolchain? — Собрать с помощью llvm и clang? Отвечаем Y или Enter если да, и N если нет. Рекомендую собирать LLVM с помощью Clang.
  • Skip build tests? Пропустить сборку тестов? Отвечаем Y или Enter. Так как во время сборки, не все тесты проходят проверку, то сборка будет прекращена. Поэтому мы пропускаем сборку тестов, и на самом деле сборка будет идти даже быстрее.
  • Skip build documentation? Пропустить сборку документации? Отвечаем Y или Enter если да, и N если нет. Если вам не нужна документация, то можно пропустить, это ускорит сборку. Лучше читать документацию на официальном сайте, это удобнее.
  • Skip build OCaml and Go bindings? Пропустить сборку OCaml и Go биндингов? Отвечаем Y или Enter если да, и N если нет. Для большинства ответ Y и их сборку можно смело пропустить в угоду скорости сборки. Для тех кому они нужны, а это очень маленькое количество людей могут ответить N.

Сборка может занять от 20 минут до пары часов. Ждете и в конце отвечаете Y на вопрос: хотите ли вы поставить собранные пакеты?

После установка LLVM надо собрать libclc12-git yay -S libclc12-git. libclc необходим для компиляции opencl и для сборки mesa.

?Делаем LLVM и Clang сборочным тулчейном по умолчанию в Arch Linux



Большинство программ в Arch Linux собираются с помощью команды makepkg: man makepkg и PKGBUILD файлов. Поэтому в первую очередь внесем изменения в конфигурационный файл /etc/makepkg.conf. Выполним под root в консоли команду: vim /etc/makepkg.conf. Перейдем к строке CHOST="x86_64-pc-linux-gnu" поставим курсор на следующей пустой строке и нажмем латинскую букву «A», и вставим после строки:

export CC=clang
export CXX=clang++
export LD=ld.lld
export CC_LD=lld
export CXX_LD=lld
export AR=llvm-ar
export NM=llvm-nm
export STRIP=llvm-strip
export OBJCOPY=llvm-objcopy
export OBJDUMP=llvm-objdump
export READELF=llvm-readelf
export RANLIB=llvm-ranlib
export HOSTCC=clang
export HOSTCXX=clang++
export HOSTAR=llvm-ar
export HOSTLD=ld.lld

Дальше заменим строки CPPFLAGS, CXXFLAGS, LDFLAGS на содержимое ниже:

CFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"
CXXFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"
LDFLAGS="-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"

Если вкратце мы используем -O2 оптимизацию для всех программ, -fstack-protector-strong используем улучшенную защиту стека, что снижает вероятность потенциально опасных ошибок при работе со стеком в программах, она же включена у меня в ядре. Плюс на моем процессоре при сборке с Clang с -fstack-protector-strong код при работе с целыми числами работает чуть быстрее, при работе с числами с плавающей запятой есть небольшой оверхед. В GCC наоборот есть более заметный оверхед и производительность снижается. -march=native есть смысл заменить на ваш, у меня это -march=znver2 gcc.gnu.org/onlinedocs/gcc/x86-Options.html.

Изменим количество потоков в MAKEFLAGS и NINJAFLAGS для сборки программ. Это помогает ускорить сборку программ. После -j надо указать количество потоков для сборки. Рекомендуется ставить ваше количество ядер или потоков процессора, если ядер 4, то ставим 4 или 8. У меня это 20, 12 ядер, 24 потока, 4 остаются запасными для других задач. Или используем автоматическое определение $(nproc).

В итоге получим:

MAKEFLAGS="-j20"
NINJAFLAGS="-j20"

или

MAKEFLAGS="-j$(nproc)"
NINJAFLAGS="-j$(nproc)"

Из DEBUG_CFLAGS и DEBUG_CXXFLAGS надо удалить -fvar-tracking-assignments. LLVM не поддерживает данный параметр.

Файл должен будет принять примерно такой вид:

CARCH="x86_64"
CHOST="x86_64-pc-linux-gnu"

CARCH="x86_64"
CHOST="x86_64-pc-linux-gnu"
#-- Compiler and Linker Flags
export CC=clang
export CXX=clang++
export LD=ld.lld
export CC_LD=lld
export CXX_LD=lld
export AR=llvm-ar
export NM=llvm-nm
export STRIP=llvm-strip
export OBJCOPY=llvm-objcopy
export OBJDUMP=llvm-objdump
export READELF=llvm-readelf
export RANLIB=llvm-ranlib
export HOSTCC=clang
export HOSTCXX=clang++
export HOSTAR=llvm-ar
export HOSTLD=ld.lld

CPPFLAGS="-D_FORTIFY_SOURCE=2"
CFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"
CXXFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"
LDFLAGS="-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"
RUSTFLAGS="-C opt-level=2"
#-- Make Flags: change this for DistCC/SMP systems
MAKEFLAGS="-j20"
NINJAFLAGS="-j20"
#-- Debugging flags
DEBUG_CFLAGS="-g"
DEBUG_CXXFLAGS="-g"
#DEBUG_CFLAGS="-g -fvar-tracking-assignments"
#DEBUG_CXXFLAGS="-g -fvar-tracking-assignments"
#DEBUG_RUSTFLAGS="-C debuginfo=2"

Нажмем ESC, дальше SHIFT + :(буква Ж). Внизу появится: — строка для ввода команд, вводим wq. w — write, записать изменения в файл. q — quit, выйти из vim. q! выход из vim без сохранения файла. Кому сложно разобраться с vim, в Linux есть замечательная программа, называется она vimtutor. Если у вас настроена правильно локаль, то vimtutor будет на русском, запустить его можно командой `vimtutor`. Стоит заметить, вопреки распространенному мнению, обучение у вас не займет много времени. Обычно новичков пугают мифом: vi и vim люди изучают очень долго, и осилить их могут только единицы. На самом деле это не так и там нет ничего сложного.

Следующим этапом можно добавить настройки в файл .bashrc текущего пользователя. Не root, сборка программ под root очень плохая идея! Это относительно вредный совет и с помощью clang будут собираться все программы! Поэтому делайте это только если хорошо понимаете зачем это вам. Это можно сделать командой:

cat << 'EOF' >> "${HOME}/.bashrc"

export CARCH="x86_64"
export CHOST="x86_64-pc-linux-gnu"
export CC=clang
export CXX=clang++
export LD=ld.lld
export CC_LD=lld
export CXX_LD=lld
export AR=llvm-ar
export NM=llvm-nm
export STRIP=llvm-strip
export OBJCOPY=llvm-objcopy
export OBJDUMP=llvm-objdump
export READELF=llvm-readelf
export RANLIB=llvm-ranlib
export HOSTCC=clang
export HOSTCXX=clang++
export HOSTAR=llvm-ar
export HOSTLD=ld.lld

export CPPFLAGS="-D_FORTIFY_SOURCE=2"
export CFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"
export CXXFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"
export LDFLAGS="-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"
export RUSTFLAGS="-C opt-level=2"
export MAKEFLAGS="-j20"
export NINJAFLAGS="-j20"
export DEBUG_CFLAGS="-g"
export DEBUG_CXXFLAGS="-g"

EOF

?Список системных библиотек и программ которые стоит собирать вручную


Внимание, сборка всех программ и все консольные команды надо выполнять под обычным пользователем, перед установкой у вас попросит пароль root. Сборка всех библиотек и программ из списка не занимает много времени. Все кроме Mesa у меня собирается в районе 1 минуты. Список дан в той в последовательности в которой рекомендуется сборка! К примеру от zlib-ng и zstd зависит Mesa, а от Mesa зависит xorg-server.

Самое первое, что надо сделать в Arch Linux это заменить zlib на zlib-ng. Это дает хороший выигрыш производительности в приложениях, которые зависят от zlib. Больше всего это заметно на веб браузерах и веб серверах, которые используют gzip сжатие для передачи данных. На высоко нагруженных серверах это дает очень значительную прибавку к производительности. Сборка довольно быстрая. Поставить можно командой(под обычным пользователем): yay -Syu zlib-ng. На вопрос хотите ли вы удалить zlib отвечайте Y. Не бойтесь библиотеки полностью взаимозаменяемы, и ничего не сломается!

Дальше у нас идет zstd это вторая по популярности библиотека используемая в ядре и в программах для сжатия данных. Поэтому имеет смысл собрать так же ее. Чтобы собрать, вам нужно скопировать содержимое zstd, создать директорию, например zstd, а в ней создать файл PKGBUILD и в него вставить содержимое по ссылке. Дальше в консоли перейти в директорию содержащую PKGBUILD, выполнить команду makepkg -cfi .

libjpeg-turbo — Библиотека для работы c jpeg файлами. Ее очень часто используют браузеры и программы рабочего стола. libjpeg-turbo собранный с clang дает у меня лучшую производительность. Действия такие же, как в zstd. Создать директорию, и вставить в файл PKGBUILD содержимое по ссылке libjpeg-turbo. Дальше в консоли перейдите в директорию содержащую PKGBUILD, выполнить команду makepkg -cfi.

libpng — Библиотека для работы с PNG файлами. По сборке и установке все то же самое. libpng. Для сборки вам понадобится патч: 72fa126446460347a504f3d9b90f24aed1365595.patch, его надо положить в одну директорию с файлом PKGBUILD. Для сборки надо внести изменения в PKGBUILD, заменить source и sha256sums на строки ниже, и добавить функцию prepare.

source=("https://downloads.sourceforge.net/sourceforge/$pkgname/$pkgname-$pkgver.tar.xz"
  "72fa126446460347a504f3d9b90f24aed1365595.patch")
sha256sums=('505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca'
  '84298548e43976265f414c53dfda1b035882f2bdcacb96ed1bc0a795e430e6a8')

prepare() {
  cd $pkgname-$pkgver
  patch --forward --strip=1 --input="${srcdir:?}/72fa126446460347a504f3d9b90f24aed1365595.patch"
}

Mesa — это святой грааль для всех графических приложений. Стоит собирать всегда вручную, дает хорошую прибавку в десктоп приложениях, улучшается отклик рабочего стола. Одно время сидел на git версии, чтобы получить лучшую поддержку новых видеокарт AMD. Вот мой PKGBUILD оптимизированный для сборки с помощью Clang.

Для сборки вам надо отредактировать файл mesa.conf и установить необходимые вам драйвера dri, gallium, vulkan для сборки. У меня сборка только под новые видеокарты AMD. Подглядеть можно тут: Mesa OpenGL, mesa-git package, Mesa Documentation. При выходе новой версии Mesa не забудьте сменить 21.1.2 на новую версию. А после смены версии обновите контрольные суммы файлов, выполнив в директории с PKGBUILD команду updpkgsums.

xorg-server — X сервер с которым взаимодействуют почти все среды рабочего стола. Сборка дает заметное улучшение отклика рабочего стола. Сборка такая же через mapkepkg -cfi. Скачать необходимые файлы для сборки можно тут: xorg-server Сборочный пакет немного кривой и собирает пакет без оптимизаций. Поэтому его надо пропатчить. Для это после строки arch-meson ${pkgbase}-$pkgver build \ надо добавить строки:

  -D debug=false   -D optimization=2   -D b_ndebug=true   -D b_lto=true   -D b_lto_mode=thin   -D b_pie=true \

Полный список критических важных программ влияющих на производительность системы вы можете посмотреть в моём github репозитории arch-packages. Список был создан с помощью системного профилировщика perf. Все сборочные файлы оптимизированы для сборки с помощью llvm и сборка полностью автоматизирована. На моем ryzen 9 3900x сборка всего занимает около 20 минут. Единственный пакет который невозможно собрать с помощью clang и llvm это glibc. Его надо собирать вручную, и с оптимизацией -march= под ваш процессор, это самая часто вызываемая библиотека. Сборку glibc могут проводить только профессионалы, понимающие, что они делают. Не правильная сборка может сломать систему!

Для того, что бы воспользоваться автоматизированной сборкой надо выполнить(под обычным пользователем):

git clone https://github.com/h0tc0d3/arch-packages.git && cd arch-packages && chmod +x build.sh

Дальше нам надо установить все gpg сертификаты и зависимости необходимые для сборки, выполним ./build.sh --install-keys, а затем ./build.sh --install-deps

Для сборки программ достаточно просто запустить скрипт: ./build.sh --install, скрипт вам будет задавать вопросы, какие программы хотите собрать и поставить. На вопрос: хотите ли вы отправить все ваши деньги и пароли автору статьи? хотите ли вы заменить программы?(например, zlib-ng и zlib конфликтуют. Удалить zlib? [y/N] ) ответьте Y . Если вам нужна принудительная пересборка всех программ, то надо выполнить ./build.sh --install --force. По умолчанию, если пакет был уже собран и найден с нужной версией, то он не собирается, а просто устанавливается.

Для сборки mesa надо отредактировать файл mesa/mesa.conf и установить необходимые вам драйвера dri, gallium, vulkan для сборки.

С помощью команды ./build.sh --check можно проверить различия версий в моем репозитории и в официальном, помогает быстро адаптировать сборочные файлы и собрать актуальные версии программ. Слева версия в моем репозитории, справа от стрелки в официальном. Мой репозиторий может служить удобной тренировочной точкой на пути к созданию своего дистрибутива, создания LFS и развитию навыка пересборки ПО не ломая систему.

[+] zstd 1.5.0-1
[+] libpng 1.6.37-3
[+] libjpeg-turbo 2.1.0-1
[+] mesa 21.1.2-1
[+] pixman 0.40.0-1
[-] glib2 2.68.3-1 -> 2.68.2-1
[+] gtk2 2.24.33-2
[+] gtk3 1:3.24.29-2
[+] gtk4 1:4.2.1-2
[+] qt5-base 5.15.2+kde+r196-1
[+] icu 69.1-1
[+] freetype2 2.10.4-1
[+] pango 1:1.48.5-1
[+] fontconfig 2:2.13.93-4
[+] harfbuzz 2.8.1-1
[+] cairo 1.17.4-5
[+] wayland-protocols 1.21-1
[+] egl-wayland 1.1.7-1
[+] xorg-server 1.20.11-1
[+] xorgproto 2021.4-1
[+] xorg-xauth 1.1-2
[+] xorg-util-macros 1.19.3-1
[+] xorg-xkbcomp 1.4.5-1
[+] xorg-setxkbmap 1.3.2-2
[+] kwin 5.22.0-1
[+] plasma-workspace 5.22.0-2
[+] glibc 2.33-5

?Сборка Ядра с помощью LLVM и Clang с LTO оптимизацией


Внимание! Сборку ядра необходимо выполнять под обычным пользователем. Перед установкой ядра у вас попросит sudo пароль. Не рекомендуется использовать патчи ядра linux-ck, linux-zen, MuQSS и т.д. Мною были протестированы все, при кажущемся увеличении производительности системы, происходят кратковременные лаги и снижается стабильность системы, некоторые подсистемы ядра работают не стабильно! С выходом ядра 5.11 стандартный планировщик работает не хуже и значительно стабильнее! Единственный патч который мною применяется это патч для применения оптимизации под процессор github.com/graysky2/kernel_gcc_patch Выбрать ваш процессор можно в меню конфигуратора ядра Processor type and features-->Processor family.

Сборка ядра с помощью LLVM описана в официальной документации Linux Kernel Build with LLVM. Но там есть несколько подводных моментов, которые не описаны. Первый подводный момент заключается в OBJDUMP=llvm-objdump, тут идет переопределение objdump, но так как параметры objdump в llvm имеет другой синтаксис, то при сборке будет пропущена часть тестов для проверки корректности сборки, и будет warning ругающийся на objdump. Правильно будет оставить родной objdump OBJDUMP=objdump

Неправильно:

make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip   READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++   HOSTAR=llvm-ar HOSTLD=ld.lld OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump

Правильно:

make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip   READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++   HOSTAR=llvm-ar HOSTLD=ld.lld OBJCOPY=llvm-objcopy OBJDUMP=objdump

Второй подводный момент заключается в том, что если мы не добавим LLVM_IAS=1 в строку make, то нам не будет доступна LTO оптимизация в конфигураторе ядра!

Поэтому полная строка для сборки с LTO будет:

export BUILD_FLAGS="LLVM=1 LLVM_IAS=1 CC=clang CXX=clang++ LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar HOSTLD=ld.lld OBJCOPY=llvm-objcopy OBJDUMP=objdump"
make ${BUILD_FLAGS} -j$(nproc)

Полный список команд для сборки ядра. /tmp
надо заменить на вашу директорию куда будут распакованы исходные файлы ядра, а mykernel
надо заменить на ваш постфикс для имени ядра.

export BUILD_FLAGS="LLVM=1 LLVM_IAS=1 CC=clang CXX=clang++ LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar HOSTLD=ld.lld OBJCOPY=llvm-objcopy OBJDUMP=objdump"
tar -xf linux-5.12.11.tar.xz -C /tmp
cd /tmp/linux-5.12.11
zcat /proc/config.gz > .config # Берем конфигурацию запущенного ядра из /proc/config.gz и используем ее для сборки
echo "-mykernel" > .scmversion
make ${BUILD_FLAGS} oldconfig
make ${BUILD_FLAGS} -j$(nproc) nconfig

C помощью oldconfig конфигурация адаптируется под новое ядро и запускается конфигуратор nconfig. Подробнее о конфигураторах ядра можно прочесть в официальной документации [Kernel configurator](https://www.kernel.org/doc/html/latest/kbuild/kconfig.html).

В конфигураторе переходим в General architecture-dependent option --> Link Time Optimization (LTO) и выбираем Clang ThinLTO (EXPERIMENTAL). Для дополнительной защиты стека в General architecture-dependent options ставим * напротив Stack Protector buffer overflow detection и Strong Stack Protector. Жмем F9 и сохраняем новый конфигурационный файл. Далее идет список команд для сборки и установки нового ядра.

make ${BUILD_FLAGS} -j$(nproc)
make ${BUILD_FLAGS} -j$(nproc) modules
sudo make ${BUILD_FLAGS} -j$(nproc) modules_install
sudo cp -v arch/x86_64/boot/bzImage /boot/vmlinuz-mykernel

Следующий подводный момент заключается в DKMS, после установки ядра собранного с помощью Clang, DKMS пытается собрать модули ядра с помощью GCC. По этой причине сборка и установка DKMS модулей в новое ядро завершается ошибкой. Решение проблемы заключается в передаче DKMS компилятора Clang таким образом:

sudo ${BUILD_FLAGS} dkms install ${dkms_module} -k 5.12.11-mykernel

?Автоматизация сборки ядра Linux


Для автоматизации сборки ядра мы будем использовать мой bash скрипт github.com/h0tc0d3/kbuild. Клонируем репозиторий и перейдем в рабочую директорию: git clone https://github.com/h0tc0d3/kbuild.git && cd kbuild && chmod +x kbuild.sh

Отредактируем файл build.sh или поместим содержимое ниже в файл ${HOME}/.kbuild. Рекомендуется второй способ vim "${HOME}/.kbuild" т.к. при обновлении скрипта наши настройки сохранятся. Если использовалось клонирование репозитория git, то в директории со скриптом можно выполнить команду git pull, чтобы обновить скрипт. Ниже даны параметры по умолчанию, они формируют поведение скрипта по умолчанию, если соответствующий параметр не был передан. Эти параметры в дальнейшем можно будет переопределить с помощью параметров командной строки для скрипта. Так же можно добавить команду в ваш .bashrc. Для этого в директории со скриптом kbuild.sh надо выполнить echo "alias kbuild='${PWD}/kbuild.sh" >> "${HOME}/.bashrc", ${PWD} автоматом заменит на текущую директорию. Или из любой другой директории можно указать полный пусть к скрипту echo "alias kbuild='полный-путь/kbuild.sh'" >> "${HOME}/.bashrc" После редактирования .bashrc необходимо перезапустить терминал! Теперь можно будет запускать скрипт командой kbuild --help .

KERNEL_VERSION='5.12.11'         # Версия Linux для сборки. Любая версия с официального сайта kernel.org, включая rc версии.
KERNEL_POSTFIX='noname'         # Постфикс для названия ядра. Ядро будет иметь имя версия-постфикс, 5.12.11-noname, нужно для разделения в системе ядер с одной версией.
KERNEL_CONFIG='/proc/config.gz' # Конфигурационный файл ядра. Поддерживает любые текстовые файлы и с жатые с расширением gz.
KERNEL_CONFIGURATOR='nconfig'   # Конфигуратор ядра nconfig, menuconfig, xconfig.
# Рекомендую использовать nconfig, он лучше menuconfig.
# Можно писать полную строку, например MENUCONFIG_COLOR=blackbg menuconfig
# Дополнительную информацию можно найти в документации к ядру https://www.kernel.org/doc/html/latest/kbuild/kconfig.html
MKINITCPIO=1 # Запускать "mkinitcpio -p конфигурационный_файл" После сборки? 0 - Нет, 1 - Да.
MKINITCPIO_CONFIG="${KERNEL_POSTFIX}" # Имя конфигурационного файла mkinitcpio, по умолчанию равно постфиксу.

CONFIGURATOR=0      # Запускать конфигуратор ядра? 0 - Нет, 1 - Да. Если вам не нужно конфигурировать ядро, то можно поставить 0.
LLVM=0              # Использовать LLVM Для сборки? 1 - Да, 0 - Нет(Будет использован GCC или другой системный компилятор по умолчанию)
THREADS=8           # Количество поток для сборки. Ускоряет сборку. Для автоматического определения надо заменить на $(nproc)
BUILD_DIR='/tmp'    # Директория в которой будет проходить сборки ядра. У меня 32gb оперативной памяти и сборка происходит в tmpfs.
DOWNLOAD_DIR=${PWD} # Директория для сохранения архивных файлов с исходниками ядра. ${PWD} - в папке из которой запущен скрипт сборки.

DIST_CLEAN=0    # Если директория с исходниками существует выполнять make disclean перед сборкой? 0 - Нет, 1 - Да
CLEAN_SOURCE=0  # Выполнять make clean после сборки ядра? 0 - Нет, 1 - Да
REMOVE_SOURCE=1 # Удалять директорию с исходными файлами ядра после сборки? 0 - Нет, 1 - Да.
SYSTEM_MAP=0    # Копировать System.map в /boot После сборки? 0 - Нет, 1 - Да.

PATCH_SOURCE=1                          # Применять патчи ядра? 0 - Нет, 1 - Да.
PATCHES=("${HOME}/confstore/gcc.patch") # Список патчей ядра. Нельзя поменять с помощью параметров скрипта.

DKMS_INSTALL=1                                        # Выполнять DKMS Install? 0 - Нет, 1 - Да.
DKMS_UNINSTALL=1                                      # Выполнять DKMS Uninstall? 0 - Нет, 1 - Да.
DKMS_MODULES=('openrazer-driver/3.0.1' 'digimend/10') # Список DKMS модулей, который нужно собрать и установить. Нельзя поменять с помощью параметров скрипта.

Внимание! Сборку ядра необходимо выполнять под обычным пользователем. Перед установкой ядра у вас попросит sudo пароль. Не рекомендуется использовать патчи ядра linux-ck, linux-zen, MuQSS и т.д. Мною были протестированы все, при кажущемся увеличении производительности системы, происходят кратковременные лаги и снижается стабильность системы, некоторые подсистемы ядра работают не стабильно. С выходом ядра 5.11 стандартный планировщик работает не хуже и значительно стабильнее! Единственный патч который мною применяется это патч для применения оптимизации под процессор github.com/graysky2/kernel_gcc_patch. Нас интересует файл more-uarches-for-kernel-5.8+.patch. Путь к нему имеет смысл указать в PATCHES. Выбрать ваш процессор можно в меню конфигуратора ядра Processor type and features-->Processor family.

Принцип работы скрипта:

1) set -euo pipefail — скрипт переходит в строгий режим, в случае ошибок скрипт завершается с ошибкой. Является хорошим тоном, при написании bash скриптов. Скрипт проверяет запущен ли он под рут, если запущен под рут, то выдает ошибку и завершается. Загружается настройки пользователя из файла ${HOME}/.kbuild

2) Скрипт проверяет существование директории linux-версия в директории BUILD_DIR. Если существует, то исходники распакованы. Перед сборкой может выполняться команда make distclean, поведение задается переменной DIST_CLEAN. Если этой директории не существует, то проверяется существование файла linux-версия.tar.gz

или linux-версия.tar.xz. Если файл найден, то он распаковывается в BUILD_DIR. Иначе файл скачивается с kernel.org в директорию DOWNLOAD_DIR.

3) Скрипт применяет патчи ядра и устанавливает постфикс для версии ядра(записывает его в файл .scmversion ).

4) Скрипт копирует настройки ядра из файла KERNEL_CONFIG в .config и выполняет make oldcofig для адаптации настроек под новое ядро и запускает конфигуратор ядра.

5) Скрипт собирает ядро и модули.

6) Скрипт удаляет модули DKMS из ядра которое сейчас запущено, если это необходимо. Это необходимо, чтобы в списке dkms status не отображались мертвые ядра. Удаляет директорию `/lib/modules/версия-постфикс` если она существует. Она существует в том случае, если мы собираем одну и туже версию несколько раз. Это дополнительная защита от unpredictable behavior .

7) Скрипт устанавливает модули ядра, копирует ядро в /boot/vmlinuz-постфикс.

8) Скрипт собирает DKMS модули и устанавливает их. Копирует System.map в /boot/System-постфикс.map, если это необходимо.

9) Обновляет загрузочный img файл для ядра. Выполняет mkinitcpio -p конфиг.

10) Выполняет make clean если необходимо. Удаляет директорию linux-версия в директории BUILD_DIR, если это необходимо.

Собрать ядро с llvm можно командой ./kbuild.sh -v 5.12.11 --llvm --start или kbuild -v 5.12.11 --llvm --start, если был установлен alias. -v 5.12.11 — указывает версию ядра для сборки, --llvm — указывает собирать ядро с помощью llvm и clang. --start — указывает, что надо запускать конфигуратор ядра. Получить справку по параметрам скрипта можно выполнив команду kbuild --help.

Русская справка
Параметры:                     Описание:              Пример:
--version, -v                  Версия ядра для сборки --version 5.12.11 | -v 5.13-rc4
--postfix, -p                  Постфикс ядра          --postfix noname | -p noname
--config, -c                   Файл конфигурации ядра --config /proc/config.gz | -c /proc/config.gz
--dir, -d                      Директории сборки      --dir /tmp | -d /tmp
--download, -z                 Директория загрузки    --download /tmp | -z /tmp
--threads, -t                  Количество потоков сборки --threads 8 | -t 8
--configurator, -x             Конфигуратор ядра      --configurator nconfig | -x "MENUCONFIG_COLOR=blackbg menuconfig"

--start, -s                    Запускать конфигуратор
--disable-start, -ds           Не запускать конфигуратор

--mkinitcpio, -mk              Запускать mkinitcpio после установки ядра
--disable-mkinitcpio, -dmk     Не запускать mkinitcpio после установки ядра
--mkinitcpio-config, -mc       Конфиг mkinitcpio      --mkinitcpio-config noname | -mc noname

--llvm, -l                     Использовать LLVM
--disable-llvm, -dl            Не использовать LLVM

--patch, -ps                   Применять патчи ядра
--disable-patch, -dp           Не применять патчи ядра

--map, -m                      Копировать System.map в /boot/System-постфикс.map
--disable-map, -dm             Не копировать System.map

--clean, -cs                   Чистить исходники после сборки. make clean
--disable-clean, -dc           Не чистить исходники после сборки.
--distclean, -cd               Чистить исходники перед сборкой. make distclean
--disable-distclean, -dd       Не чистить исходники перед сборкой.
--remove, -r                   Удалять директорию с исходниками после сборки
--disable-remove, -dr          Не удалять директорию с исходниками после сборки

--dkms-install, -di            Устанавливать DKMS модули
--disable-dkms-install, -ddi   Не устанавливать DKMS модули
--dkms-uninstall, -du          Деинсталлировать DKMS модули перед их установкой
--disable-dkms-uninstall, -ddu Не деинсталлировать DKMS модули перед их установкой

Список параметров которые помогают отлавливать ошибки на разных этапах и продолжить вручную:

--stop-download, -sd           Стоп посл загрузки файла
--stop-extract, -se            Стоп после распаковки архива с исходниками
--stop-patch, -sp              Стоп после применения патчей ядрей
--stop-config, -sc             Стоп после конфигуратора ядра
--stop-build, -sb              Стоп после сборки ядра
--stop-install, -si            Стоп после установки нового ядра и модулей


Как можно понять из статьи сборка ядра с LLVM и Clang относительно простая. И самое главное можно автоматизировать сборку и установку ядра, и в дальнейшем не тратить много времени на сборку новых ядер.

Всем кто дочитал до конца, спасибо! Комментарии и замечания приветствуются!

UPD. 16.06.2021 Обновил сборочные скрипт библиотек и программ, производительность еще выросла github.com/h0tc0d3/arch-packages


Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Была ли полезна и понравилась вам статья?

  • 77,1%Да, статья понравилась и была полезна64
  • 16,9%Нет, статья не понравилась и не была полезна14
  • 6,0%Другое, ответ в комментарии5

Продолжить серию статей по оптимизации Linux?

  • 86,2%Продолжить серию статей81
  • 11,7%Не продолжать серию статей11
  • 2,1%Другое, ответ в комментарии2




Комментарии (55):

  1. lorc
    /#23147784 / -1

    «LTO оптимизация» — это «Link Time Optimization оптимизация»?

    • nullc0de
      /#23147802 / +2

      Да. Вы наверное про масло масленое «optimization оптимизация»? Так было написано для лучшего понимания русскоговорящему человеку.
      llvm.org/docs/LinkTimeOptimization.html
      gcc.gnu.org/wiki/LinkTimeOptimization

      • lorc
        /#23148050

        < del >

        • nullc0de
          /#23148078 / +3

          Вы не поняли, а вот вас понял сразу. Был просто раскрыт термин LTO для понимания его смысла. Потому что на русском нормально написать LTO оптимизация. В тексте было просто раскрытие термина. Это было сделано в первую очередь для тех кто не знаком с терминологией. На самом деле очень долго подбирал слова, чтобы текст был понятен не профессионалам, и чтобы профессионалов не задеть. В том предложении поэтому остановился на таком варианте. Масло масленое заметил еще когда писал статью, но остановился на таком варианте написания.

  2. alsoijw
    /#23148226

    Представьте себе, что у вас исходный код программы занимает несколько гигабайт, такой размер нередко встречается в серьезных программах
    Например?
    Оптимизированное дерево может быть преобразовано в машинный псевдокод понятный компилятору.
    Скорее всего это не псевдокод, а байткод.

    Статье не хватает бенчмарков. Так же непонятен вопрос обновления — запускается ли автоматическая пересборка или нет. Так же вопрос, почему выбран бинарный дистрибутив.

    • nullc0de
      /#23148314

      Например?

      alsoijw
      du -sh /tmp/linux-5.12.10/
      1,2G /tmp/linux-5.12.10/


      Скорее всего это не псевдокод, а байткод.

      Да LLVM IR. LLVM использует свой язык описания для описания многих структур поэтому псевдокод не является ошибкой. Пример github.com/llvm/llvm-project/commit/5b149c437194d10877e9e45b3d8cc9252af1944b

      Статье не хватает бенчмарков. Так же непонятен вопрос обновления — запускается ли автоматическая пересборка или нет.

      perf в помощь. У меня лично загрузка процессора упала при вызове API ядра. Пересборка остальных программ где-то быстрее где-то медленнее. В общем дало выигрыш хороший, упала загрузка процессора, стало меньше потребление памяти, анимации стали плавнее и производительнее. Сложно оценивать производительно современных компиляторов, в одни программах код будет быстрее в других наоборот. У меня есть бенчмарки для себя, где-то GCC выигрывает почти в 2 раза в скорости, где-то clang оказывается в раза 2 быстрее. clang в первую очередь дает более прогнозируемый код и не ломает поведение. Мне известны случаи когда GCC ломал поведение программ в случае переоптимизации, и поэтому разработчики программ отключали некоторые типы оптимизаций. Как знаю, в случае с рекурсивными вызовами их производительность будет увеличена в LLVM 13, но рекурсия в принципе является плохим тоном программирования и лучше ее избегать, переписывать алгоритм где есть возможность.

      Так же непонятен вопрос обновления — запускается ли автоматическая пересборка или нет.

      Не запускается, мой скрипт просто уменьшает количество действий, при установке все равно нужен sudo пароль. В принципе можно в крон или системд его прописать под рутом, и убрать проверку рута. Но сборка под рутом является плохим тоном.

      Так же вопрос, почему выбран бинарный дистрибутив.

      Мне не нужно собирать все. Дистрибутив выбран по принципу самое свежее ПО. Критические программы у меня собираются вручную. Arch Linux для этого хорошо создан и все делается удобно, можно автоматизировать сборку. У меня сборка всего критического автоматизирована, плюс где-то есть патчи которых нет в официальных пакетах github.com/h0tc0d3/arch-packages

      • alsoijw
        /#23148450

        Пересборка остальных программ где-то быстрее где-то медленнее. В общем дало выигрыш хороший, упала загрузка процессора, стало меньше потребление памяти, анимации стали плавнее и производительнее.
        Вот это хочется увидеть в конкретных цифрах.
        Мне не нужно собирать все.
        Существуют дистрибутивы с бинарным кешем, позволяющие пересобирать конкретные программы. В этом случае, пересборка будет происходить при обновлении системы автоматически, без костылей с кроном, там будет отдельный пользователь для сборки и так далее.

        • nullc0de
          /#23148482

          alsoijw вы можете про это написать статью, с радостью вас почитаем. Мною было написано про то чем пользуюсь сам и давно. Мне как разработчику clang больше нравится как компилятор так как он лучше ловит ошибки в коде и проблемы оптимизации. Переходить обратно на GCC ради бенчмарков мне просто лень. На clang перешли FreeBSD и MacOS и лично это только поддерживаю. Все проблемы медленного кода можно удобно отловить в clang, переписать код и улучшить производительность, тем самым просто убрать разрыв там где gcc быстрее, в gcc этого нет. Для меня в первую очередь производительность зависит от разработчика, а не от компилятора или языка программирования. Для себя предпочитаю полу автоматический режим, могу накатить патчи, протестировать что-то, быть уверенным, что не будет такого, что сборка сломает систему когда меня не будет рядом. Всегда могу быстро откатить систему назад.

      • Aldrog
        /#23150826

        Мне известны случаи когда GCC ломал поведение программ в случае переоптимизации, и поэтому разработчики программ отключали некоторые типы оптимизаций.

        Вот, кстати, никогда не понимал такую практику / советы. Если оптимизация ломает программу, значит в коде есть ошибка и надо её исправить. Иначе она может точно также неожиданно проявиться потом из-за какой-нибудь другой оптимизации при обновлении компилятора, причём независимо от того GCC это или Clang, а может даже и без оптимизаций на каких-нибудь других входных данных.

        • slonopotamus
          /#23151000

          Если оптимизация ломает программу, значит в коде есть ошибка и надо её исправить.

          Вопрос в том в коде чего ошибка - в коде компилируемой программы или в коде компилятора.

          • Aldrog
            /#23151594

            Гораздо чаще это ошибка именно в коде программы. Если это всё-таки ошибка компилятора, то конечно имеет смысл отправить баг-репорт и временно отключить оптимизацию (до выхода патча).
            Понятно, что отключить оптимизацию сильно проще, чем искать ошибку, но это крайне безответственный подход (в первую очередь по отношению к качеству своего продукта). Очень сомневаюсь, что в том же Linux именно так и делают.

        • alsoijw
          /#23151506

          Вы так говорите, как будто очевидно, в какой именно строке какая именно ошибка. А дальше уже вопрос ресурсов для поиска этой ошибки.

          • nullc0de
            /#23151560

            alsoijw человек просто перепутался в ошибках компилятора и ПО, ошибки компилятора посложнее ловить и ПО не всегда может их решить. Проблемы производительности ПО через профилировщик видно, в дальше можно просто посмотреть на ошибки оптимизации этого куска кода, компилятор при передаче определенных параметров может показывать такие ошибки, в clang это делать удобно. Ошибки компилятора это сложнее, чаще всего он предустановлен и даже если сделают быстро патчи, то не факт что они быстро появятся в дистрибутиве… Только на днях видел в каком-то пакете багрепорт связанный с GCC, и там отсылка на сам баг в GCC. У меня были тоже подобные баги с LLVM, но у меня git версия и патчи сразу переношу в свой пакет aur.archlinux.org/packages/llvm12-git
            Вот к примеру баг llvm с которым лично столкнулся и там даже отписался bugs.llvm.org/show_bug.cgi?id=49915

            • Aldrog
              /#23151736

              Если честно, не верю, что ошибки компилятора, проявляющиеся в некорректной оптимизации корректного кода (не ломая процесс сборки), встречаются достаточно часто, чтобы сделать осмысленным совет отключать оптимизации не разбираясь в проблеме. Лично я с такими вообще ни разу не сталкивался, у вас по ссылке тоже судя по всему не тот случай.


              Вот ограниченность ресурсов — очевидно корректный аргумент, но только если качеству продукта достаточно низкий приоритет отдаётся.

              • nullc0de
                /#23151800

                Aldrog вы в принципе мало понимаете в разработке компиляторов, столкнетесь с компиляторами ужаснетесь от багов))) Никогда не слышали про баги GCC c -funroll-loops? wiki.gentoo.org/wiki/GCC_optimization/ru Некоторые оптимизации дают сбой, их компилятор чаще всего отключает, отсюда может быть потеря производительности. Компилятор старается оценить сложность оптимизации, если во время оптимизации оказывается, что сложность оптимизации высокая, то он может отказаться от оптимизации или вовсе создать не корректный код. Начиная с gcc 9 включили агрессивное разворачивание циклов по умолчанию, и довольно много тогда было багрепортов, что ПО работает не везде корректно. Довольно сложно в компиляторах предусмотреть все возможные ошибки оптимизации. Тот же full lto в случае сложности оптимизации тупо генерирует много кода и код наоборот становится медленнее. Поведение всех компиляторов очень отличается. На мой вгляд в этом плане самый умный clang.

                • Aldrog
                  /#23152046

                  Не спорю ни с наличием багов в компиляторах, ни с отсутствием опыта разработки последних, спорю только с тем, что с ними легко столкнуться просто включив -O3.


                  Впрочем, теперь я понял, что именно вы представляете как преимущество clang.
                  Не раз встречал на хабре мнение, что любые агрессивные оптимизации — это некорректная работа компилятора, поэтому долго не мог понять, что вы имеете в виду под "корректностью работы -O3" и "поломкой поведения программ".

            • alsoijw
              /#23152110

              У меня были тоже подобные баги с LLVM, но у меня git версия и патчи сразу переношу в свой пакет aur.archlinux.org/packages/llvm12-git

              И как, принимали патчи? А то я в своё время отправил тривиальный патч, а потом выяснил, что данная проблема уже поднималась, и присылался гораздо более полный патч, однако его так и не приняли, просив доработать. А потом, после нескольких правок с ним, как и с моим всё заглохло.

              • nullc0de
                /#23152454

                В компиляторы у меня не было патчей. В других проектах принимали, и так же отклоняли по разным причинам. Все сильно зависит от мейнтейнера. Где-то замечательные программисты и с радостью идут на диалог, помогут и принимают патчи, где-то совсем наоборот. Не мало раз было, что присылал патч и говорили в следующем релизе этого куска кода не будет и уже алгоритм переписан.

  3. VioletGiraffe
    /#23148436

    А что с производительностью, какие-то бенчмарки выполнялисьс дефолтным и самосборным ядрами? Интересно, есть ли какое-то ускорение работы от перехода на clang.

    • nullc0de
      /#23148440

      VioletGiraffe комментарием выше есть уже ответ на ваш вопрос. Судя по perf у меня есть улучшение общей производительности. В общем система стала стабильнее, пропала дерготня, особенно в анимациях kde и в хромиум, рендеринг и загрузка вебстраниц происходят заметно быстрее.

      • yarston
        /#23148978

        Очень странно, что Ryzen 9 3900x + AMD Radeon 5700 XT не вытягивает базовую анимацию рабочего стола без дерготни. У меня такого даже на дохлом атоме не было в те времена, когда LLVM никто всерьёз не воспринимал.

        • nullc0de
          /#23148994

          yarston ничего странного. Кривая оптимизация может даже быть из-за неправильного разворачивания кода GCC. Плюс некоторые пакеты имеют плохую оптимизацию, а где-то вовсе криво собираются в Arch Linux. Поэтому мною были созданы свои сборочные файлы. До mesa 21 и ядра 5.10 моя видеокарта плохо поддерживалась, сейчас все стало лучше. До сих пор в ядре есть где AMD не совсем корректно работает, например управление электропитанием. Ядро под Intel лучше оптимизировано. Но вот что радует AMD нанимает разработчиков и с каждым месяцем ситуация меняется в лучшую сторону. Вообще графический стек это самое слабое место Linux, у меня к примеру в хромиум не работает hardware acceleration. Проблема уходит корнями далеко в прошлое, поэтому сейчас активно пытаются развивать wayland, но для меня он сырой еще, у меня с ним кучу багов, поэтому от него пришлось пока отказаться community.kde.org/Plasma/Wayland_Showstoppers

          • alsoijw
            /#23149792

            Очень странно, что Ryzen 9 3900x + AMD Radeon 5700 XT не вытягивает базовую анимацию рабочего стола без дерготни.
            Скорее всего, это проблемы KDE и Xorg, хотя я натыкался и на проблемы с GNOME. Порой складывается впечатление, что разработчики этих сред сами их не используют, так как в других средах, например Mate данных проблем нет.
            меня к примеру в хромиум не работает hardware acceleration
            В чём проблема? Vaapi не включается? Что насчёт firefox?

            • nullc0de
              /#23149898

              В некоторых пакетах разработчики просто кладут на всех. Пишешь им багрепорты, а они забивают и даже не отписываются. Есть не мало адекватных, которые патчи быстро делают. Но так же не мало кто забивает на критические ошибки, мне даже самому не редко приходилось писать патчи потому что авторы забивали болт. В линукс есть такая штука, что старые разработчики боятся иноваций и всячески этому мешают, готовы поддерживать 30 летние компы, но отказываются от растущего рынка новых, например так было с автором zlib-ng когда его патчи не приняли в zlib, разработчики xorg не очень идут на помощь wayland и не спешат решать общие проблемы. Радует что mesa и ядро развиваются хорошо, привносят инновации и выкинули мертвые код для старых систем, чтобы открыть новым лучшую производительностью

              Canvas: Hardware accelerated
              Compositing: Hardware accelerated
              Multiple Raster Threads: Enabled
              Out-of-process Rasterization: Disabled
              OpenGL: Enabled
              Rasterization: Software only. Hardware acceleration disabled
              Skia Renderer: Enabled
              Video Decode: Software only. Hardware acceleration disabled
              Vulkan: Disabled
              WebGL: Hardware accelerated
              WebGL2: Hardware accelerated

    • alsoijw
      /#23148458

      Я пересобирал ядро, так как хотел включить один флаг. Пересборка была довольно долгой, так что я решил отключить очевидные флаги. В результате незначительно, на несколько десятков мегабайт увеличился максимально доступный объём памяти.

    • junari
      /#23149476 / +1

      На phoronix были тесты llvm и gcc: https://www.phoronix.com/scan.php?page=article&item=clang12-gcc11-icelake&num=6

      Если кратко, то победил llvm clang в 63% тестов, в среднем быстрее на 9% чем gcc.

      • gudvinr
        /#23150472 / +1

        По большей части Clang победил в бесполезных тестах на нейросети, которые редко на CPU считают.
        В более-менее полезных задачах преимущество, в основном, у GCC, да и то незначительное.

        • nullc0de
          /#23151324

          Перечитайте статью с самого начала, и пройдитесь по результатам каждого теста, у вас немного не правильные выводы.

  4. vanyas
    /#23148572

    Про русскую букву Ж это конечно пять. Вы всерьёз думаете что собирать таким образом ядро пойдет человек который не знает vim и не может найти двоеточие на клавиатуре?

    • nullc0de
      /#23148608 / -1

      Почему нет? Собрать ядро с LTO нет ничего сложного. Насчет vi и vim первая сложность в обучении это как выйти из них и как перейти в режим ввода команд, дальше обучение очень простое. По этой причине многие не пользуются ими и не понимают их. Владение vi и vim никак не показатель опыта и не маркер владения Linux. Человек может всю жизнь пользоваться nano и знать Linux лучше вас. Статья в первую очередь для тех кто хочет обучиться большему.

      • mayorovp
        /#23150268

        Тем не менее, я считаю что в подобном туториале по сборке ядра было бы уместнее использовать более интуитивные редакторы, чтобы не отвлекаться от собственно сборки ядра.

  5. Gorthauer87
    /#23148876

    Что-то мне кажется, что для таких опытов лучше подойдёт Gentoo.

    • nullc0de
      /#23148884

      Gorthauer87 без разницы, хоть многое у меня собирается вручную, большая часть это бинарные пакеты дистрибутива. У меня все собирается и обновляется за минимальное и вполне адекватное время, и без напряга. Подойдет в принципе любой дистрибутив, просто написал про тот с которым мне удобнее работать. Основная задача статьи открыть дополнительные горизонты для оптимизации, где их будут применять в принципе без разницы. Хоть в centos 7 и на сервере в продакшене, в принципе стабильности всех решений достаточно для серверов. Ядро с clang собираю давно и стабильность системы имхо выше, LTO тестирую с 5.12.6 и ничего не ломалось, стабильность хорошая. Часть пакетов в arch linux и так собирается с LTO и GCC, просто переписал сборочные файлы под lto thin и clang.

    • ProFfeSsoRr
      /#23160516

      для таких опытов лучше подойдёт Gentoo.
      а в генту сейчас можно поставить вообще всю остальную систему из бинарных пакетов за несколько минут (при наличии шустрого интернета)? Арч тем и хорош, что он бинарный — но свежий, и свои пакеты собирать легко. Поэтому можно экспериментировать с чем хочешь, а с чем не хочешь — ставить из репо готовое. Много-много лет назад я именно поэтому его и выбрал.

      • alsoijw
        /#23164158

        Это к форкам, например, Calculate. Или можно попробовать NixOS(это не форк, но имеет множество подходящих для данной задачи свойств).

  6. NewTechAudit
    /#23149472 / +1

    Спасибо за хорошую и полезную статью!

  7. lurker
    /#23149646 / +1

    За всё время знакомства с арчем не заходил дальше сборки git версий из AUR и пересборки в ABS. А после прочтения статьи — прямо захотелось повторить. Спасибо за статью!

  8. wataru
    /#23150170

    И ни слова, собственно, о том, что эта самая LTO вообще делает. Что компилятор там может оптимизировать? Функции местами переставлять? Инлайнить функции?

  9. event1
    /#23151502

    Следующий подводный момент заключается в DKMS, после установки ядра собранного с помощью Clang, DKMS пытается собрать модули ядра с помощью GCC. По этой причине сборка и установка DKMS модулей в новое ядро завершается ошибкой.

    Интересно, почему модули собранные GCC не работают с ядром, собранным clang. Ведь, по идее, между ними только заголовки ядра (при компиляции) и бинарный интерфейс (при загрузке). Падает, я так понимаю, именно загрузка, да? Получается clang укладывает структуры или делает вызовы по-другому? Или у него другой формат .ko-файлов?

    • nullc0de
      /#23151598

      event1 честно говоря не знаю. Cамая частая ошибка c llvm и lto, что o файлы содержат LLVM IR, а его могут обработать только тулчейны llvm. Эта ошибка бывает когда сборочные скрипты пытаются использовать другой ld, ranlib, ar. Уже не помню ошибку с DKMS, так как эта ошибка была еще давно до lto, видимо была тоже причина в этом.

      • event1
        /#23151774 / +1

        да, но ведь тут clang собирает ядро, а его .o-файлы не нужны для DKMS. Ядро же не ожидает .ko-файлы с LLVM IR, правда? Это было бы очень удивительно.

        • nullc0de
          /#23151834

          event1 нет не ожидает, и там нет ужe IR, там видимо просто о файлы линкуются в ko. Позже гляну, что за ошибка там и отпишу конкретно уже.

          • event1
            /#23151918

            А-а-а. То есть он ядерные clang-овые аргументы пытается в gcc скормить. Интересно… Наверное можно DKMS научить использовать другие, не-ядерные, аргументы.

  10. vvzvlad
    /#23168948

    Скажите, а без vim ничего работать не будет, да?

    • nullc0de
      /#23169146

      Будет. Можете использовать любой удобный вам текстовый редактор.

      • vvzvlad
        /#23169202

        Тогда какой смысл в пересказе руководства по vim, вместо того, чтобы просто описать, что должно быть в файлах? Или переменная дефолтного редактора ускользает от понимания?

        • nullc0de
          /#23169218 / -1

          А где вы там нашли пересказ руководства по vim? Вас это как-то задевает или vim не осилили? Или может у вас скролл на мышке сломался? В чем проблема? Если вам это не было полезно, не значит, что другим так же. Вам же не указываю как писать вам ваши статьи, откуда столько негатива к vim?

          • vvzvlad
            /#23169228

            Ну это как в руководстве по переборке двигателя вдруг сделать отступление и начать рассказывать как работать с разводным ключом. Малость бессмысленно — если уж человека заинтересовала переборка двигателя, то с ключом, будь он ему нужен, он и сам разберется. А если он предпочитает накидной — то ему тем более эта информация как пятая нога.

            • nullc0de
              /#23169276

              Не похоже, так драматизируете будь-то скролл на мышке сломался…
              Вам может не нравится, но вот знаете, книжки для чайников имеют очень высокий рейтинг продаваемости, а все потому, что там пишут и объясняют самые простые вещи. И самое главное мне отписалось в личку несколько людей, которые не работают с линуксом, но заинтересовалось им благодаря статье. Если не верите могу скинуть скрины переписки. Рейтинг одобрения у статьи 85,9% и 76,8% это говорит о многом. Так что можете дальше завидовать и плеваться ядом, не зная к чему еще придраться. Еще и карму минусуете. Позорище.

              • vvzvlad
                /#23169286

                Ох, как бомбит. Ладно, явно диалог не имеет смысла.

                • nullc0de
                  /#23169294

                  Бомбит вас, и видимо очень сильно, что не ограничились одним комментарием и даже минусанули карму, а мною лишь констатируются факты.

  11. schw0reismus
    /#23169136

    Оказывается, можно в CFLAGS и CXXFLAGS добавить -flto=thin, и тогда автоматом всё будет собираться с тонкой оптимизацией. Возможно, ещё куда-то.

    • nullc0de
      /#23169144

      Можно, но я бы не рекомендовал это делать в makepkg.conf или .bashrc или .profile.
      В моих сборочных скриптах он добавлен, но не везде, только где я смог заставить его работать, и где смог сделать патчи, переписать сборочные скрипты или где мне разработчики сделали патчи на мой запрос. Мои сборочные скрипты сильно отличаются от тех, что в официальном репо. И не мало пакетов просто так не собирается с -flto.