Формула турбореактивного ускорения: ускоряем компиляцию приложений с помощью ccache и distccСборка приложений из исходников процесс для юниксоида обычный и даже обыденный. Мы компилируем приложения, чтобы опробовать новый функционал, наложить патчи или просто установить пакет в систему (привет поклонникам BSD и Gentoo). Однако современные приложения настолько велики, что порой этот процесс может занять не один час. Чтобы не ждать так долго, предлагаю воспользоваться специальными утилитами, которые могут существенно сократить время сборки приложений. Вообще, способов повышения скорости сборки приложений в никсах несколько, и не все они требуют использования дополнительного софта. Один из наиболее простых и прямолинейных способов заключается в отключении любых флагов оптимизации. Этот шаг действительно дает существенный выигрыш в скорости сборки, но также приводит к заметному снижению скорости исполнения скомпилированного софта. Если ты согласен с таким положением вещей, то можешь приказать компилятору принудительно отключать любые оптимизации. Для этого добавь следующие строки в свой ~/.bashrc:
Пользователи FreeBSD и Gentoo могут использовать файл /etc/make.conf для изменения значения этих переменных:
В OpenBSD файл носит имя /etc/mk.conf. Ускорить процесс компиляции можно с помощью распараллеливания, то есть одновременной компиляции сразу нескольких файлов, содержащих исходный текст. Те, кто знаком с программированием, должны знать, что любая более-менее крупная программа, написанная на языке Си, состоит из нескольких обособленных файлов, содержащих фрагменты исходного кода. Во время сборки программы эти файлы обрабатываются компилятором независимо и лишь в самом конце объединяются линковщиком в единый исполняемый файл. Благодаря этой особенности сборку приложения можно распараллелить так, чтобы эти фрагменты-файлы компилировались одновременно. Подавляющее большинство приложений с открытым кодом используют make в качестве утилиты, контролирующей все этапы сборки. Make принимает флаг '-j', позволяющий задать количество одновременных потоков компиляции (на самом деле, он указывает на количество параллельно выполняемых задач, но мы не будем вдаваться в подробности). Правильно устанавливая значение этого флага, мы можем существенно повысить скорость сборки приложения на многоядерных процессорах. Так, если твой камень четырехъядерный, то оптимальное значение флага '-j' будет равно… пяти. Все верно, опытным путем доказано, что «лишний» поток еще больше ускоряет процесс. Причем то же верно и для одноядерных систем, для которых рекомендуемым значением будет 2. В «классических линуксах» флаг '-j' следует указывать прямо во время сборки приложения:
В системах, основанных на портах, есть специальные опции конфигурационного файла, позволяющие задействовать этот флаг глобально. Например, в Gentoo любые опции make можно прописать в переменную MAKEOPTS файла /etc/make.conf. Во FreeBSD эта переменная носит имя MAKE_ARGS. В тех же «source based» дистрибутивах можно задействовать другой трюк, позволяющий сократить время сборки в среднем на 10%. Смысл его в том, чтобы поместить каталог, используемый для хранения промежуточных результатов компиляции, в tmpfs. Скорость доступа к файлам существенно возрастет, что и приведет к выигрышу. Большинство систем использует для хранения временных файлов один из подкаталогов /var/tmp, поэтому нам достаточно просто примонтировать к нему tmpfs. Пример для Gentoo:
Естественно, машина должна обладать достаточным объемом памяти (2 Гб вполне хватит), чтобы tmpfs не начала использовать swap, что еще более растянет процесс компиляции. Если же памяти в системе мало, то ее можно освободить с помощью завершения всех «толстых» приложений и выхода из иксов. КэшированиеПо умолчанию компилятор не обращает внимания на ранее скомпилированные файлы и производит полную перекомпиляцию всего приложения во время повторного запуска процесса сборки. Это может сильно навредить, если ты, например, многократно исправляешь один из файлов исходников и каждый раз после этого инициируешь сборку. Это также увеличит время экспериментов с ядром, когда ты несколько раз пересобираешь ядро, пробуя включать и выключать различные опции. Для решения проблемы можно воспользоваться услугами ccache. Программа ccache – это кэширующий препроцессор, который позволяет избежать повторной компиляции уже скомпилированных ранее файлов. Он генерирует хеш для каждого компилируемого файла, поэтому если с момента предыдущей компиляции файл остается неизменным, его повторная обработка не производится, а используется уже ранее скомпилированный объектный файл. Ccache позволяет существенно поднять скорость повторной компиляции приложения. В некоторых случаях прирост может составлять десятки раз.
Закэшированные препроцессором объектные файлы хранятся в каталоге ~/.ccache. По умолчанию его размер ограничен 1 Гб, но я бы порекомендовал увеличить его до 4 Гб:
Если места в домашнем каталоге будет недостаточно для хранения кэша, ты можешь указать ccache использовать другой каталог:
Для верности создай симлинк:
Особое место ccache занимает в системах, основанных на портах. Компиляция утилит, необходимых только во время сборки порта, статических библиотек и других «одноразовых» инструментов, в таких системах обычно осуществляется каждый раз во время сборки порта, их требующего. Поэтому ccache приносит неоценимую пользу. К тому же, уже существующие в кэше файлы могут быть повторно использованы при обновлении портов. Ниже приводится два рецепта использования ccache: в дистрибутиве Gentoo и в ОС FreeBSD. Для активации ccache в Gentoo достаточно выполнить два простых действия: 1. Установить ccache: 2. Отредактировать файл /etc/make.conf: После выполнения этих действий все порты будут собираться с использованием ccache. Чтобы активировать ccache во время сборки ядра с помощью genkernel, следует использовать следующую команду:
В случае с FreeBSD все несколько сложнее, но вполне в рамках разумного: 1. Устанавливаем ccache: 2. Редактируем /etc/make.conf: 3. Редактируем ~/.cshrc (или ~/.bashrc): Для отключения ccache во время сборки определенного порта используем такую команду вместо стандартного «make install clean»:
Распределенная компиляцияУвеличить скорость компиляции можно с помощью привлечения к этому процессу других машин. Я не говорю сейчас о сборке приложения на более мощной машине с последующим копированием результата на менее производительную (хотя это тоже вариант), я говорю об организации кластера из машин, каждая из которых будет принимать участие в сборке одного приложения. Поднять такой кластер достаточно просто, и для этого мы воспользуемся инструментом под названием distcc. Distcc – это обертка для gcc, которая позволяет задействовать мощности других машин для увеличения скорости компиляции приложения. В отличие от других решений этого класса, distcc прост в установке и не требует модификации исходного кода приложения или каких-либо подготовительных действий. На удаленную машину передается уже обработанный препроцессором исходный код, поэтому со своей стороны она не должна иметь каких-либо заголовочных файлов или библиотек для проведения успешной компиляции. Кластер distcc обычно состоит из одного клиента и нескольких серверов. Клиент запускается на машине, инициирующей процесс сборки, и передает задания на выполнение компиляции серверам, работающим на удаленных машинах. Задание состоит из обработанного препроцессором файла, содержащего исходный код, и флагов компилятора. Все это отправляется на сервер с помощью обычного сетевого соединения без какого-либо шифрования и аутентификации удаленной стороны. Серверы, фактически выполняющие компиляцию, могут работать под управлением операционных систем Linux, *BSD, Solaris или Windows (потребуется установка gcc и distcc в окружение cygwin), однако версия gcc на этих машинах должна быть одинаковой. Нет смысла использовать distcc для одноразовой сборки приложения, с этим вполне справится и один комп. Зато в дистрибутиве Gentoo и ОС FreeBSD он может дать заметный прирост в скорости установки и обновления приложений. Gentoo уже подготовлен для использования distcc, поэтому его владельцам достаточно выполнить несколько простых шагов для активации обертки. Сначала установим distcc на все машины кластера:
Далее переходим на машину-клиент и редактируем файл /etc/make.conf:
В опции MAKEOPTS указываем общее количество потоков компиляции. Обычно это число высчитывается следующим образом: общее количество процессоров/ядер на всех машинах * 2 + 1. Однако это не всегда верно, и, возможно, придется поэкспериментировать, чтобы подобрать оптимальное значение. Для задания хостов, участвующих в компиляции, воспользуемся утилитой distcc-config (на самом деле, она всего лишь модифицирует значение переменной DISTCC_HOSTS):
Вместо IP-адресов можно использовать DNS-имена машин. Чтобы более равномерно распределить нагрузку по машинам, через слэш после адреса машины ты можешь указать одновременное количество заданий, которое она может принять. Например, если на машине 192.168.0.1 установлен четырехъядерный процессор, то общее количество заданий для нее лучше установить в пять: 192.168.0.1/5. Далее на всех машинах необходимо запустить сервер. Для этого отредактируем файл /etc/conf.d/distccd, чтобы разрешить выполнение заданий, полученных от клиентов нашей подсети:
Теперь добавим сервер в дефолтовый уровень запуска и запустим его:
Теперь все порты будут компилироваться в кластере distcc. Чтобы собрать ядро с использованием distcc, используй следующую команду:
В отличие от Gentoo, FreeBSD не обладает инфраструктурой, необходимой для прозрачного внедрения distcc, поэтому нам придется вживлять его хирургическим путем. Для этого установим distcc с помощью системы портов:
Это нужно сделать на всех машинах, которые будут участвовать в процессе компиляции. Далее активируем сервер distcc в /etc/rc.conf так, чтобы он запускался во время инициализации ОС и мог принимать задания от клиента:
Этот шаг также необходимо выполнить на всех машинах, включая клиентскую (чтобы компиляция происходила и на машине, ее инициировавшей). Флаг '--allow' задает подсеть, машины которой имеют право отправлять задания серверу. Запускаем сервер: Возвращаемся на клиентскую машину. Открываем файл /etc/make.conf и добавляем в него следующие строки:
Мы указали distcc в переменных CC и CXX, благодаря чему порты и мир будут автоматически собираться в кластере, для распределения сборки всего остального пойдем на небольшой трюк и подменим стандартные компиляторы gcc и g++:
Откроем /root/.cshrc и поместим созданный нами каталог в начала путей поиска бинарников:
Туда же поместим инициализацию переменной DISTCC_HOST, которая будет содержать адреса distcc-серверов:
Все, для проверки можно запустить сборку какого-либо порта. Пакет distcc поставляется вместе с утилитой для мониторинга процесса сборки distccmon-text. Запустив программу без параметров, ты увидишь на экране текущее состояние distcc. Чтобы получать сведения в режиме реального времени, используй команду «distccmontext N», где N – это интервал в секундах между выводом информации на экран. Пользователи Gnome (и не только) могут воспользоваться графическим монитором под названием distccmon-gnome. Не все порты могут быть прозрачно собраны с использованием distcc. В Gentoo они явно помечены как «нераспределяемые», поэтому сборка будет происходить только на машине-клиенте. Во FreeBSD все сложнее, здесь нет интеграции с distcc, поэтому при возникновении проблем со сборкой первым делом следует отключить distcc, закомментировав строку опции CC и CXX в /etc/make.conf и убрав /usr/local/ lib/distcc/bin из путей поиска бинарников. Компиляция в облакеПрограмма distcc становится эффективным решением, когда речь заходит о сборке приложения в кластере машин, размещенных в локальной сети, но в силу своей незащищенности она не может быть применена для распределения компиляции по машинам, разбросанным по всему миру. Ты можешь создать частную VPN, чтобы обойти эту проблему, но я предлагаю более простое и эффективное решение – SSH-туннель. Все нижеприведенные инструкции актуальны для дистрибутива Gentoo, но не составит большого труда подогнать их под другой дистрибутив/ОС. Для начала активируем пользователя distcc. Он автоматически создается во время установки порта, но не может выполнять вход в систему. Чтобы организовать туннель между машинами, нам нужно это исправить. Во-первых, пользователь должен иметь домашний каталог (пусть будет /etc/distcc):
Во-вторых, ему должен быть назначен шелл:
В-третьих, он должен быть разлочен:
Эти три шага необходимо проделать на всех машинах. Чтобы клиент мог логиниться на машины-рабочие с использованием ssh и
Публичный ключ (id_dsa.pub) необходимо скопировать в каталог /etc/distcc/.ssh/authorized_keys всех машин, которые будут участвовать в компиляции. Чтобы ssh и portage смогли работать совместно, придется исправить права доступа. На машинах-рабочих выполняем команды:
На клиенте выполняем команды:
Чтобы во время выполнения emerge ssh не застрял на полпути с вопросом о принятии публичного ключа каждой машины-рабочего, заранее соберем все эти ключи:
Теперь создадим обертку для distcc:
Сделаем ее исполняемой:
Отредактируем файл /etc/make.conf: Это все. Удачной компиляцииТакие программы, как ccache и distcc, вкупе с другими трюками, могут дать весьма существенный прирост в скорости сборки, однако ты должен иметь в виду, что не все приложения могут быть собраны с их помощью. Сборка некоторых сложных программ, состоящих из многих компонентов, часто завершается ошибкой, причину которой трудно идентифицировать. Поэтому будь внимателен, используй последнюю версию ccache и одинаковые версии gcc на машинах distcc-кластера, кроме того, не забывай заглядывать в файл INSTALL. Info
|