diff --git a/docs/linux/assets/distccmon-text.png b/docs/linux/assets/distccmon-text.png new file mode 100644 index 0000000..2d2eb10 Binary files /dev/null and b/docs/linux/assets/distccmon-text.png differ diff --git a/docs/linux/distrant.md b/docs/linux/distrant.md new file mode 100644 index 0000000..9f50c7b --- /dev/null +++ b/docs/linux/distrant.md @@ -0,0 +1,288 @@ +# Немного про распределенную компиляцию + +> В телеграмме про распределенные и параллельные вычисления + +## Мотивация / Введение + +Про `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 на удалённых машинах, что ускоряет процесс компиляции. + +Важно понимать, что это своего рода фронтенд для компиляторов, +сам по себе он не компилирует код. + +## Компиляция + +### Демонстрация стенда + +Для начала построчно рассмотрим 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) + с исходным кодом ядра (должен лежать в директории с Vagrantfile). + +Конфигурация второстепенных машин: + +``` + # 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` и далее. Сделано это на случай нескольких ВМ. + +### Компиляция на одной машине (gcc) + +Для начала запустим стенд командой `vagrant up`. На моем ноутбуке это занимает +примерно 127 секунд. + +Далее необходимо подключиться к главной машине и распаковать исходники ядра[^3]: + +``` +vagrant ssh master +tar xvf linux-6.13.tar.gz +cd linux-6.13 +``` + +Создаем файл минимальной конфигурации +(с остальными вариантам можно ознакомиться командой `make help | less`): + +``` +make tinyconfig +``` + +> **Важно**: для чистоты эксперимента все замеры делаются после команды `make + distclean` (см. `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 | + +## Итог + +Можно увидеть, что такая параллелизация дает прирост 37%. +Сложно сказать, можно ли разогнать сильнее, так как многое зависит от +правил компиляции (например, их нельзя распараллелить больше чем на 5 потоков). + +Очевидно, что распределенная компиляция при прочих равных будет проигрывать +параллельной, так как общение между потоками по определению быстрее. +Но для слабых машин это отлично подходит. К сожалению, у данного метода есть +существенные ограничения: + +1. Версии gcc и distcc должны совпадать (хотя, пишут, что достаточно + совпадения только мажорных версий). +2. В некоторых случаях нет возможности общения по TCP и требуется подключение по + SSH. Например, когда есть ограничения безопасности или при сложной организации + сети. Определенно, такое подключение будет медленнее. + +Все материалы стенда можно найти в +[репозитории](https://github.com/rustbas/disgrant/) на Github. + +[^1]: Википедия [Vagrant](https://ru.wikipedia.org/wiki/Vagrant). +[^2]: Википедия [distcc](https://ru.wikipedia.org/wiki/Distcc). +[^3]: Исходный код ядра можно найти [здесь](https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.13.tar.gz). diff --git a/docs/linux/index.md b/docs/linux/index.md index 4bfe419..77e8672 100644 --- a/docs/linux/index.md +++ b/docs/linux/index.md @@ -2,3 +2,4 @@ ## 2024-11-01 [Немного про мануалы](manpage.md) +## XXXX-XX-XX [Немного про распределенную компиляцию](distrant.md)