Ускоряем компиляцию пакетов. Советы и используемые мною трюки.

За что я люблю Gentoo? За потрясающую гибкость и возможность улучшить практически всё!

Подозреваю, что многие пользователи Calculate перешли на него с Gentoo именно за возможность избежать долгих часов компиляции. Я и сам, признаться, руководствовался в том числе и этим мотивом. Бывают ситуации, когда компилировать просто некогда, бывает железо, превращающее процесс в мучение… Однако далеко не всё богатство софта в portage наличествует у нас в бинарном виде. В результате совсем от компиляции уйти не удаётся. Кроме того, иногда из перфекционистских соображений пользователь может отказаться от бинарных пакетов. Например чтобы избавиться от ненужного лично ему, но присутствующего на диске софта, языков, на которых он не говорит, не читает и не пишет, добавить отсутствующий по умолчанию функционал или наоборот, от части функционала избавиться. Всё это влечёт за собой изменение USE флагов и, как следствие, пересборку из исходников.

Предлагаемые ниже советы и трюки помогут ускорить этот процесс.

Про железо.

  • Самый важный элемент Вашего компьютера, ускоряющий компиляцию - ОЗУ. Нужно больше памяти! Swapping Ваш враг, swapping крадёт минуты и часы из Вашей жизни, swapping портит Ваш характер. Ряд советов из приведённых здесь предполагают наличие у Вашего компьютера “лишнего” ОЗУ. Память нынче дешёвая, увеличить ОЗУ до комфортных размеров, хотя бы до 16 гигабайт, и навсегда забыть про swapping стоит совсем недорого, зато сразу же улучшится цвет лица и качество Вашей жизни.
  • SSD. Вы ещё не переехали всей системой на SSD диск? Дорого? Купите что нибудь быстрое и дешёвое на 60gb и осильте bcache. Получите “два в одном”, ёмкость Вашего “классического” HDD плюс сверхбыстрый случайный доступ свойственный SSD. Рекомендую.
  • А вот процессор, как ни странно, лишь на третьем месте… Тут всё понятно, мне кажется. Чем больше всего, ядер, частот, кэша - тем лучше.

Про помогающий софт, глобальные флаги и tmpfs.

* Кроме компиляции часть времени отнимают процессы распаковки\запаковки - распаковка исходников, сжатие чего нибудь в процессе установки… В portage есть версии популярных архиваторов использующие многопоточные алгоритмы: app-arch/pbzip2 и app-arch/pigz - многопоточный gzip. Если установить их с флагом symlink они подменят собою штатные bzip2 и gzip. Есть разные мнения об их эффективности, но почему бы не попробовать? Вы ничего не сломаете, если что то пойдёт не так - просто удалите эти пакеты и продолжите пользоваться штатными.

* Смонтируйте PORTAGE_TMPDIR в tmpfs.
У меня в fstab:

none            /var/portagetmp tmpfs   mode=1777,size=10G,mpol=interleave      0 0

/var/portagetmp - это у меня так. Замените Вашим значением переменной PORTAGE_TMPDIR.
size=10G - вполне достаточно для сборки libreoffice например. Реально в памяти tmpfs занимает столько места, сколько на ней данных. При размере ОЗУ в 16gb и tmpfs 10gb openoffice собирается без залезания в swap. Если памяти будет не хватать, ОС начнёт вытеснять неиспользуемые страницы tmpfs в swap. Это чревато тормозами, но ничего не сломается.
mpol=interleave - не обращайте внимания, Вам можно это не писать, это мои NUMAпроблемы.
Не используйте _pipe_ в CFLAGS если Вы собираете в tmpfs, зачем вам двойной расход памяти. И наоборот, не используете tmpfs пропишите -pipe в CFLAGS.

* Флаг pch - использование прекомпилированных заголовков, существенно ускоряет сборку qt программ и библиотек. Имеет смысл включить его глобально. Внимание! Этот флаг ломает сборку при использовании distcc и снижает эффективность ccache!

* ccache. Есть ошибочное мнение что использование ccache ускоряет компиляцию. В долгосрочном плане это не так. Эффективность “холодного” кеша ccache весьма низка, наличие в “холодном” кеше объектов от сборки предыдущей версии пакета вряд ли поможет при сборке новой версии. Возможный выигрыш растрачивается на работу алгоритма поиска по массиву кеша (поэтому нет смысла делать размер кеша больше умолчального) и доступ к диску для каждого вызова gcc, даже если это SSD. Он всё равно медленнее чем доступ к ОЗУ (о сборке в tmpfs мы поговорим позднее). Поэтому если у Вас глобально выставлено FEATURES=“ccache” в make.conf вы замедляете сборку, а не ускоряете. ccache необходим, если Вы отлаживаете сборку какого либо пакета и она постоянно прерывается ошибками. Вот в этом случае использование FEATURES=“ccache” ebuild /путь/к-тому/что-вы/чините.ebuild merge или FEATURES=“ccache” emerge уже-компились-давай оправданно и экономит время. Несмотря на всё вышесказанное, я использую один трюк с ccache слегка убыстряющий обновление мира. Дело в том, что ccache может эффективно ускорять прохождение этапа configure. На этом этапе система гоняет тесты, большинство из которых однотипные и их результаты прекрасно живут, не вытесняясь, в горячем кеше. Как это работает: Я монтирую CCACHE_DIR в tmpfs, руками, перед обновлением мира, и задаю кешу маленький размер, 100mb. В результате я жертвую 100mb ОЗУ, но получаю ускорение тестов configure. Для этого у меня в fstab есть запись:

none            /var/cache/ccache       tmpfs   size=1G,noauto       0 0

/var/cache/ccache - я предпочитаю хранить кеш тут, из эстетических соображений, переменная CCACHE_DIR в make.conf указывает у меня туда. Там живёт холодный кеш умолчального размера, которым я пользуюсь при отладке сборки своих ebuildов.
size=1G - перестраховка, в памяти будет <=100mb.
noauto - я монтирую это вручную.
В результате я обновляю мир так:

 # mount /var/cache/ccache
 # CCACHE_SIZE=100m FEATURES=ccache emerge -auD --newuse world
umount /var/cache/ccache #когда всё закончил.

Можно конечно всё это автоматизировать, но мне лень :slight_smile:

* distcc явно выходит за рамки этой статьи. Читать здесь. Главное, что стоит помнить: не используйте use флаг pch при сборке с помощью distcc, выключите его глобально для надёжности (-pch) и нельзя использовать -march=native в СFLAGS совместно с distcc! У машин в кластере наверняка отличаются процессоры, CFLAGS в данном случае следует указывать явно и полностью. Для определения “правильных” CFLAGS для Вашей машины сделайте на ней:

 # gcc -march=native -E -v - </dev/null 2>&1 | grep cc1
 # gcc -Q --help=target -march=native

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

* Наверняка вы читали про MAKEOPTS в make.conf. Наиболее часто приводимое значение –jobs={КОЛИЧЕСТВО_ЯДЕР_ПРОЦЕССОРА}+1, одно ядро с гипертредингом считать за два ядра. Однако это не самая оптимальная настройка. Утилита make, которой и передаётся этот параметр, умеет сама регулировать количество задач в зависимости от загрузки системы. В результате получаем более эффективное распределение нагрузки. Ограничивающий нагрузку параметр называется –load-average, усреднённая загрузка системы, и для грамотной настройки необходимо понимать, сколько это в цифрах в Вашем случае и как вообще это считать. Прочитать про LA можно здесь. Эмпирически наиболее эффективное с точки зрения максимальной производительности значение -load-average_ = КОЛИЧЕСТВО_ЯДЕР+1. То есть для двухядерной машины оптимальное значение 3, для восьмиядерной 9. Но необходимо ещё учитывать расход ОЗУ - в случае его нехватки даже при теоретически правильно рассчитанном значении-load-average_ машина будет уходить в swap, показатель LA расти, эффективность - падать. И наоборот, если ОЗУ с избытком, значение –load-average можно увеличить, очередь заданий станет длиннее, средняя загрузка ядер равномернее. Итак, в конечном виде переменная может выглядеть так:

MAKEOPTS="--jobs=10 --load-average=5"

Для четырёхядерной машины это означает следующее: количество заданий make будет колебаться от 1 до 10, make будет стараться поддерживать среднюю загрузку системы в районе 5 единиц - лёгкий перегруз для четырёхядерной машины, но, при наличии вменяемого количества ОЗУ (8-16gb), не доставляющий дискомфорта при параллельном серфинге по Сети. Не увлекайтесь высокими значениями –jobs, make начинает балансировку не моментально, в результате машина может помереть в страшном свопе до того как make притормозит “лишние” потоки. Экспериментируйте.

* У portage тоже есть аналогичная настройка, только она балансирует количество процессов emerge. Получается параллельный emerge. Предположим наш ebuild собирается в один поток, поскольку параллелится с помощью make далеко не всё, некоторые программы валятся при параллельной сборке и их майнтейнеры принудительно выставили –jobs=1 в ebuild, некоторые ebuild вообще не используют make и т.п. В этом случае portage будет обеспечивать равномерную загрузку системы запуская выполнение ebuildов параллельно! В make.conf это может выглядеть так (для четырёхядерной машины):

EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --jobs=10 --load-average=5 --verbose --keep-going "

–jobs и _-load-average_ работают аналогично примеру с MAKEOPTS, применённые совместно эти настройки дополняют друг друга. Если ebuild параллелится make будет стараться поддерживать баланс нагрузки наравне с portage, если нет - portage запустит больше параллельных ebuildов. К сожалению механизм работает не со 100% эффективностью: встречаются цепочки ebuild которые должны собираться строго друг за другом и при этом внутри не распараллеливаются. Часть ядер в этом случае будет простаивать.
–keep-going удобен при параллельной сборке. Если один ebuild в процессе отвалится с ошибкой сборка остальных будет продолжена, кроме тех пакетов которые прямо зависят от помершего ebuild. Такое случается иногда (редко) при параллельной сборке из за глюков с очерёдностью. Паниковать в этом случае не надо, достаточно заново запустить сборку мира после того как она остановится и то что отвалилось в итоге соберётся.
Учитывайте расход памяти. Экспериментируйте и ищите оптимальные для Вас значения.

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

уточнение по поводу пункта

…Если памяти будет не хватать, ОС начнёт вытеснять неиспользуемые страницы tmpfs в swap. Это чревато тормозами, но ничего не сломается.

а если у нас swap-раздел физически просто отсутствует? все рухнет?

Сергей Сиделев писал(а):

уточнение по поводу пункта

…Если памяти будет не хватать, ОС начнёт вытеснять неиспользуемые страницы tmpfs в swap. Это чревато тормозами, но ничего не сломается.

а если у нас swap-раздел физически просто отсутствует? все рухнет?

Придёт OOM killer и что нибудь убьёт. Скорее всего компиляция и рухнет.

Скоратить время компиляции, по идее должен переход на clang

Все, вы уверены? Как на счет portage? :slight_smile: