# Немного про распределенную компиляцию > В телеграмме про распределенные и параллельные вычисления > В конце про версии `gcc` > В конце ссылка на репозиторий > В итоге про tcp и ssh ## Мотивация / Введение Про `gentoo` и распределенные системы. Мне, как любителю Linux всегда было интересно установить Gentoo Linux. На это есть множество причин, сейчас не о них. Суть в том, этап установки системы на виртуальную машину пройден и есть желание попробовать установить на маломощный нетбук. Возникает проблема: Gentoo Linux -- это т.н. "source-based" дистрибутив, т.е. она распространяется в виде исходного кода. В свою очередь, компиляция системы на нетбуке занимает чуть больше суток (возможно, это можно поправить более тщательной конфигурацией перед сборкой, но, на мой взгляд, это слишком "хардкорный" путь). Таким образом, возникает вопрос -- можно ли ускорить компиляцию? Тут на помощь приходит `distcc`, своего рода фронтенд для компиляторов C/C++. Здесь мы хотим посмотреть на возможность компиляции ядра Linux (минимальной конфигурации `tinyconfig`) на двух виртуальных машинах с разными характеристиками. Но для этого нужно рассказать про утилиту `vagrant`, конфигуратор виртуальных машин. ## Vagrant Vagrant[^1] (с англ. — «бродяга») — свободное и открытое программное обеспечение для создания и конфигурирования виртуальной среды разработки. Является обёрткой для программного обеспечения виртуализации, например VirtualBox, и средств управления конфигурациями, таких как Chef, Salt и Puppet. Данная утилита полезна тем, что позволяет, используя шаблоны виртуальных машин, запускать их. Для описания стэка требуется один т.н. Vagrantfile. Она может работать совместно с qemu, VirtualBox, VMWare и пр. О vagrant стоит знать потому, что в какой момент, эксперементируя с виртуальными машинами, надоест каждый раз их устанавливать в условном VMWare. ## Distcc distcc[^2] (от англ. distributed C/C++/ObjC compiler) — инструмент, позволяющий компилировать исходные коды при помощи компиляторов C/C++/ObjC на удалённых машинах, что ускоряет процесс компиляции. ## Компиляция - [x] Демонстрация стенда - [ ] Компиляция на одной машине (gcc) - [ ] Компиляция на одной машине (distcc) - [ ] Компиляция на нескольких машинах (distcc) - [ ] Таблица сравнения ### Демонстрация стенда Для начала построчно рассмотрим Vagrantfile. Используется язык Ruby. Описание "шаблона" для виртуальных машин. В данном случае это Debian 12 Bookworm. ```ruby # Default box box_name = "debian.jessie64.libvirt.box" ``` Файл можно скачать с сайта HashiCorp. Описание виртуальной машины, на которой будет основная компиляция: ``` # Master master_node = { :hostname => "master", :ip => "10.200.1.2", :memory => 1024, :cpu => 1 } ``` Характеристики: - IP: 10.200.1.2 - RAM: 1Gb - 1 поток Это почти похоже на характеристики моего нетбука, но они занижены в целях демонстрации. Описание второстепенной виртуальной машины: ``` # List of slaves slaves = [ { :memory => 4096, :cpu => 4 }, ] ``` Характеристики: - RAM: 4Gb - 4 потока Скрипт для автоматической установки зависимостей: ``` $distcc_install = <<-SCRIPT apt update apt install -y make distcc gcc g++ tmux libz-dev git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison time neofetch SCRIPT ``` Старт конфигурации виртуальных машин: ``` Vagrant.configure("2") do |config| ``` Конфигурация основной машины: ``` # Master node's config config.vm.box_check_update = false config.vm.define master_node[:hostname] do |nodeconfig| nodeconfig.vm.box = box_name nodeconfig.vm.hostname = master_node[:hostname] nodeconfig.vm.network(:private_network, ip: master_node[:ip]) nodeconfig.vm.provision "shell", inline: $distcc_install nodeconfig.vm.provision "file", source: "./linux-6.13.tar.gz", destination: "~/linux-6.13.tar.gz" nodeconfig.vm.provider :libvirt do |vb| vb.memory = master_node[:memory] vb.cpus = master_node[:cpu] end end ``` В нем: 1. Отключаются обновления, 2. Задаются характеристики ВМ, 3. Запускается скрипт установки зависимостей, 4. Копируется [архив](https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.13.tar.gz) с исходным кодом ядра. Конфигурация второстепенных машин: ``` # Slaves configs slaves.each_with_index do |slave, i| config.vm.box_check_update = false config.vm.define "slave-#{ i+1 }" do |nodeconfig| # Default box-name (cause I have only it) nodeconfig.vm.box = box_name # Hostname: slave-N nodeconfig.vm.hostname = "slave-#{ i+1 }" # IP-address: 10.200.1.{N+2} nodeconfig.vm.network :private_network, ip: "10.200.1.#{ i+3 }" nodeconfig.vm.provision "shell", inline: $distcc_install nodeconfig.vm.provider :libvirt do |vb| vb.memory = slave[:memory] vb.cpus = slave[:cpu] end end end end ``` Стоит обратить внимание, что IP задается автоматически, начиная от `10.200.1.3` и далее. Сделано это на случай нескольких ВМ. ### Компиляция на одной машине Для начала запустим стенд командой `vagrant up`. На моем ноутбуке это занимает примерно __ секунд. Далее необходимо подключиться к главной машине и распаковать исходники ядра: ``` vagrant ssh master tar xvf linux-6.13.tar.gz cd linux-6.13 ``` Создаем файл минимальной конфигурации (с остальными вариантам можно ознакомиться командой `make help | less`): ``` make tinyconfig ``` > **Важно**: для чистоты эксперимента все замеры делаются после команды `make clean` (см. `make help`). Запускаем компиляцию с замером времени: ``` time -p make CC=gcc ``` ### Одна машина (distcc) По смыслу, все тоже самое, только нужно указать distcc, на каких хостах можно компилировать: ```sh export DISTCC_HOSTS="localhost" ``` Запускаем компиляцию с замером времени: ``` time -p make CC="distcc gcc" ``` ### Две машины (distcc) Для запуска распределенной компиляции, нужно сначала запустить демон на второй виртуальной машине. Для этого подключаемся к ней и запускаем его: ``` vagrant ssh slave-1 distccd --daemon --allow-private ``` Параметр `--allow-private` разрешает стучаться только с приватных сетей. Для проверки можно: 1. На второй машине проверить открытые порты: `ss -ntlp | grep 3632` 2. На основной машине постучаться в этот порт: `telnet 10.200.1.3 3632` (выход на `C-] C-d`) Теперь нужно добавить хост, чтобы на нем можно было удаленно компилировать. Для этого на основной машине: ``` export DISTCC_HOSTS="localhost 10.200.1.3" ``` Для проверки можно посмотреть список хостов для компиляции: `distcc --show-hosts`. Запустим компиляцию на 5 потоках с замером времени: ```sh time -p make -j5 CC="distcc gcc" ``` Мониторить компиляцию можно с помощью команды (на основной машине): ``` watch -n 1 distccmon-text ``` ![distccmon-text](assets/distccmon-text.png) ### Таблица сравнения |Итерация|Одна машина (gcc), с|Одна машина (distcc), с|Две машины (distcc), с| |:------:|:------------------:|:---------------------:|:--------------------:| | 1 | 176 | 176 | 111 | | 2 | 186 | 162 | 109 | | 3 | 187 | 174 | 127 | |Среднее | 183 | 170 | 115 | [^1]: Википедия [Vagrant](https://ru.wikipedia.org/wiki/Vagrant). [^2]: Википедия [distcc](https://ru.wikipedia.org/wiki/Distcc). ## Итог 37%