Merge branch 'dev'
This commit is contained in:
BIN
docs/linux/assets/distccmon-text.png
Normal file
BIN
docs/linux/assets/distccmon-text.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 255 KiB |
288
docs/linux/distrant.md
Normal file
288
docs/linux/distrant.md
Normal file
@@ -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
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Таблица сравнения
|
||||||
|
|
||||||
|
|Итерация|Одна машина (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).
|
||||||
@@ -2,3 +2,4 @@
|
|||||||
|
|
||||||
## 2024-11-01 [Немного про мануалы](manpage.md)
|
## 2024-11-01 [Немного про мануалы](manpage.md)
|
||||||
|
|
||||||
|
## XXXX-XX-XX [Немного про распределенную компиляцию](distrant.md)
|
||||||
|
|||||||
Reference in New Issue
Block a user