Разработка на "дровах", часть вторая
Современные Java, Node.js, Eclipse, VSCode, PostgreSQL, DBeaver, Spring, Hibernate, Typescript, Angular, Webpack — все это в действии, в живую, для реальной разработки и на ноутбуке.. из 2007 года.
— Просто купите уже себе Mac, неудачники!
— Не надо экономить на спичках, 128Гб памяти хватит на всех — то что нужно для комфортной разработки.
— Ну требует современная программа хорошее оборудование, паадумаешь. Просто докупите, это нормально.
— Оптимизация это коупинг для нищебродов.
Павел в тот день был в ударе и сыпал уничижительными постами как из рога изобилия.
Но только ошибся форумом, на свою погибель.
Мы начинаем КВН
В первой части, вышедшей в далеком 2023м году я показал современную разработку на старом ноутбуке, но «совершил стратегическую ошибку» — использовал FreeBSD, еще и сделав упор на ее тюнинге.
На что получил отзывы из серии «вы BSD-шники все такие», заодно обнаружив, что для многих хардкорных сисадминов является нормой использование для повседневной работы куда более устаревших моделей ноутбуков.
Сделав выводы, повторяю подвиг эксперимент на обычном 64-битном Linux Debian и рассказываю именно про современную разработку, не админство.
История
Если честно, даже история создания этой статьи доставляет, поскольку за время подготовки материала прошел год и успела выйти новая версия Debian Linux — дистрибутива, который не славится частыми релизами.
А еще успела окончательно сдохнуть батарея, замену которой хоть и с трудом, но все же удалось достать в Москве.
Да, я смог достать новую батарею для ноутбука из 2007 года в конце 2025го.
Вот настолько я упорот крут и теперь наконец представляю вам этот шедевр.
Видео
Зачем и кому оно надо
После выхода первой части в далеком 2023м, самый частый запрос (помимо настойчивых предложений похоронить несчастный девайс с почестями и салютом) который мне задавали, звучал так:
н#хуя все это надо, когда можно пойти и купить новый Macbook
Затем мировую экономику начало штормить, начался весь этот безумный угар по ИИ, из-за которого выросли цены на видеокарты, а затем и на оперативную память и SSD-диски.
И внезапно даже до далеких от ИТ обывателей начало доходить, что праздник бесконечного роста и процветания закончился:
«печатная машинка» для просмотра порносайтов не должна стоить кучу денег, а браузер — не должен отжирать все доступные ресурсы.
Люди начали считать деньги, гигабайты и мегабиты.
Короче, на момент написания этих строк, вопрос «зачем» мне задавать перестали, зато начали внимательно читать и конспектировать.
— Боже что случилось.. Где это я?
— Почему я связан? И.. где моя одежда?
Не каждый может сохранить самообладание и трезвость мысли, очнувшись голым и связанным на дне глубокой ямы в темном подвале.
Так что у Паши точно был повод для паники.
Внезапно где-то наверху открылась тяжелая железная дверь. Павел задрав голову вверх, увидел двух неизвестных в белых балахонах.
На балахонах была яркая надпись: C64
— Неужели меня похилили сектанты?
The "девайс"
У ноутбука очень интересная судьба — он попал в мои руки фактически на убой, как реквизит.
Одно время автор занимался с каскадерами и однажды мы захотели поставить сцену с разносом офиса, где одним из разбиваемых предметов должен был стать какой-нибудь старый неработающий ноутбук.
Закончить свою трудовую жизнь красивым ударом об стену — все же лучше чем на свалке, согласитесь.
У знакомых ремонтников был выклянчен подходящий девайс в состоянии полутрупа, который было не жалко.
Сцену в итоге так и не поставили, а реквизит остался.
Поскольку я питаю определенный интерес к старым железкам — было принято решение оживить:
Аппарат помыли, почистили, вставили SSD-диск и новую батарею.
С тех пор он используется для разнообразных сотонинских обрядов и колдовства технических экспериментов и написания статей, в том числе и этой.
Бобер, который смог: бекпорт Golang на Windows 7
IOCCC или что такое элитный код
Бекпорт: запускаем Node.js v20 на Windows 7
Профессиональная разработка на.. Brainfuck
Разработка на "дровах" или FreeBSD на очень старом железе
..были написаны прямо на этом самом аппарате целиком, включая создание кода, компиляцию, портирование и так далее.
Технические характеристики
Стандартные для тех лет 15.6 экран, двухядерный мобильный процессор AMD Turion 64 X2, полноценная дискретная видеокарта ATI Mobility Radeon X2300 и 3Гб памяти — можно сказать топовая машинка для 2007 года.
Если честно, то ныне можно найти куда более современный ноутбук на обычной помойке, если немного поискать:
И конечно же аппараты этой серии или тех лет постоянно мелькают в объявлениях на Авито и на различных барахолках:
Думаю идею вы поняли, «за бутылку пива» — так это называется.
На развес еще не продают, но второй такой девайс в нагрузку за полцены уже настойчиво предлагают.
Вниз начали спускать ведро с водой.
Медленно, рывками и расплескивая воду на стены, ведро ехало вниз, будучи привязанным к веревке.
— Оно должно умываться и подмываться.
Произнес скрипучий механический голос сверху. Павел понял, что впереди очень тяжелый день.
Жестокий тюнинг
Очевидно, что без серьезного тюнинга использовать столь винтажный аппарат для чего-то отличного от показа музейных брошюр не получится.
Уж тем более с 64-битным софтом и для задач современной разработки.
Но поскольку я кое-что понимаю в жестоком тюнинге и считаю что «машины должны страдать» — ниже вас ждет весьма занимательное чтиво.
Итак, что именно мы будем использовать:
Это классический современный проект, с бекэндом на Java + Spring + Hibernate и фронтэндом на Typescript и Angular, плюс СУБД PostgreSQL.
Все это под управлением Debian Linux.
все выше будет разрабатываться с помощью современных IDE — Eclipse и VSCode
Которые собственно и требуют все эти гигабайты и гигабиты.
Java + Node.js были выбраны, поскольку это самый тяжелый по требуемым ресурсам вариант, от самой среды выполнения и до средств разработки — все требует конских ресурсов.
Тяжее этого современного говна только мобильная разработка и нейросети, поэтому запуск и того и другого на «музейном экспонате» — темы для моих новых замечательных статей.
Если исходить из рекомендуемых требований для разработки на таком стеке, то «в среднем по больнице» это что-то вроде Core i9 и 32Гб памяти на компьютере разработчика.
Мы же будем использовать AMD Turion 64 X2 — примерный аналог Intel Core 2 Duo и 3Гб памяти. На все.
Получается примерно в десять раз меньше вычислительных ресурсов, чем используют нормальные люди.
Ядро
Одним из ключевых факторов успеха столь упоротого предприятия является ядро, особенное ядро:
XanMod is a general-purpose Linux kernel distribution with custom settings and new features. Built to provide a stable, smooth and solid system experience.
Если в двух словах, то это специальный набор патчей для ядра Linux, на тему большей отзывчивости на десктопе. Поставляется в виде готового архива исходников ядра, с уже наложенными патчами.
Но поскольку мы настоящие партизаны имеем дело с компьютером, который старше вашей девушки — одного только XanMod не хватит.
Да, речь опять о знаменитом l9, про который уже есть отдельная статья. Именно его снова придется наложить на версию ядра от Xanmod, причем вручную.
Мы будем использовать версию 6.18 LTS от Xanmod, поскольку оригинальный патч l9 давно заброшен — его суть придется переносить вручную.
За основу снова взята последняя версия для ядра 5.15, но стоит пояснить, что переносить будем не все изменения.
Первым делом ищем в файле include/linux/mm.h вот эту строку:
extern unsigned long sysctl_admin_reserve_kbytes;
Сразу после которой добавляем вот эти переменные:
extern unsigned long sysctl_anon_min_kbytes; extern unsigned long sysctl_clean_low_kbytes; extern unsigned long sysctl_clean_min_kbytes;
Следущий файл для правки mm/Kconfig , ищем menu "Memory Management options" и добавляем:
config ANON_MIN_KBYTES int "Default value for vm.anon_min_kbytes" depends on SYSCTL range 0 4294967295 default 0 help This option sets the default value for vm.anon_min_kbytes sysctl knob. config CLEAN_LOW_KBYTES int "Default value for vm.clean_low_kbytes" depends on SYSCTL range 0 4294967295 default 0 help This option sets the default value for vm.clean_low_kbytes sysctl knob. config CLEAN_MIN_KBYTES int "Default value for vm.clean_min_kbytes" depends on SYSCTL range 0 4294967295 default 0 help This option sets the default value for vm.clean_min_kbytes sysctl knob.
Наконец последний файл для правки mm/vmscan.c , находите строчку unsigned int proactive:1; после которой добавляете:
/* The anonymous pages on the current node are below vm.anon_min_kbytes */ unsigned int anon_below_min:1; /* The clean file pages on the current node are below vm.clean_low_kbytes */ unsigned int clean_below_low:1; /* The clean file pages on the current node are below vm.clean_min_kbytes */ unsigned int clean_below_min:1;
Следующая правка ниже, в этом же файле, искомая строка #ifdef ARCH_HAS_PREFETCHW, но добавить необходимо перед, а не после:
unsigned long sysctl_anon_min_kbytes __read_mostly = CONFIG_ANON_MIN_KBYTES; unsigned long sysctl_clean_low_kbytes __read_mostly = CONFIG_CLEAN_LOW_KBYTES; unsigned long sysctl_clean_min_kbytes __read_mostly = CONFIG_CLEAN_MIN_KBYTES;
Следующая правка, тоже в этом же файле и самая сложная.
Надо найти метод get_scan_count, в нем вот такое условие:
if (sc->file_is_tiny) {
..
}/*
* Force-scan anon if clean file pages is under vm.clean_low_kbytes
* or vm.clean_min_kbytes.
*/
if (sc->clean_below_low || sc->clean_below_min) {
scan_balance = SCAN_ANON;
goto out;
}Дальше в этом же методе ищем строку:
nr[lru] = scan;
/*
* Hard protection of the working set.
*/
if (file) {
/*
* Don't reclaim file pages when the amount of
* clean file pages is below vm.clean_min_kbytes.
*/
if (sc->clean_below_min)
scan = 0;
} else {
/*
* Don't reclaim anonymous pages when their
* amount is below vm.anon_min_kbytes.
*/
if (sc->anon_below_min)
scan = 0;
}Следующая правка также объемная, надо найти метод:
static void shrink_node_memcgs
Затем добавить перед ним следующий код:
static void prepare_workingset_protection(pg_data_t *pgdat,
struct scan_control *sc)
{
/*
* Check the number of anonymous pages to protect them from
* reclaiming if their amount is below the specified.
*/
if (sysctl_anon_min_kbytes) {
unsigned long reclaimable_anon;
reclaimable_anon =
node_page_state(pgdat, NR_ACTIVE_ANON) +
node_page_state(pgdat, NR_INACTIVE_ANON) +
node_page_state(pgdat, NR_ISOLATED_ANON);
reclaimable_anon <<= (PAGE_SHIFT - 10);
sc->anon_below_min = reclaimable_anon < sysctl_anon_min_kbytes;
} else
sc->anon_below_min = 0;
/*
* Check the number of clean file pages to protect them from
* reclaiming if their amount is below the specified.
*/
if (sysctl_clean_low_kbytes || sysctl_clean_min_kbytes) {
unsigned long reclaimable_file, dirty, clean;
reclaimable_file =
node_page_state(pgdat, NR_ACTIVE_FILE) +
node_page_state(pgdat, NR_INACTIVE_FILE)+
node_page_state(pgdat, NR_ISOLATED_FILE);
dirty = node_page_state(pgdat, NR_FILE_DIRTY);
/*
* node_page_state() sum can go out of sync since
* all the values are not read at once.
*/
if (likely(reclaimable_file > dirty))
clean = (reclaimable_file - dirty) << (PAGE_SHIFT - 10);
else
clean = 0;
sc->clean_below_low = clean < sysctl_clean_low_kbytes;
sc->clean_below_min = clean < sysctl_clean_min_kbytes;
} else {
sc->clean_below_low = 0;
sc->clean_below_min = 0;
}
}static void shrink_node
prepare_scan_control(pgdat, sc);
prepare_workingset_protection(pgdat, sc);
Утолив жажду и умывшись, Павел стал ждать что будет дальше.
Пустое ведро, привязанное к веревке начало подниматься, будучи вытягиваемым неизвестными сектантами.
Вскоре вниз спустили веревочную лестницу.
Смирившись со своей судьбой, Павел начал медленно подниматься наверх.
Наверху его ждали два мордоворота в белых балахонах. Помимо C64, балахоны были расписаны и другими незнакомыми Павлу надписями: Amiga, Commodore, 8bit
— Какие блин 8 бит? У всех нормальных людей уже давно 64..
Мысли Павла путались, внезапно он заметил огромный плакат:
Мультяшная Эльза из «Холодного сердца» добивает мечом терминатора Т-1000, на фоне апокалиптических пейзажей.
Подпись гласила: МАШИНЫ ДОЛЖНЫ СТРАДАТЬ
Eclipse
Единственная современная среда разработки, которую можно реально использовать на столь устаревшей машине.
Конечно Netbeans и Intellij Idea тоже вполне себе запускаются, но ввиду внутреннего устройства (кучи фоновых операций) и интерфейса на Swing — тормозят столь сильно, что любая работа становится невозможной.
Eclipse использует свой особенный и главное нативный UI-тулкит SWT, поэтому действительно более-менее шевелится на столь устаревшем железе.
Для ускорения запуска, я добавил в файл eclipse.ini такие параметры:
-Xverify:none -XX:TieredStopAtLevel=1
Параметры весьма спорные и даже где-то опасные, поскольку первым отключается валидация class-файлов перед загрузкой в виртуальную машину, что и дает серьезное ускорение.
Разумеется у такого решения есть своя цена в виде снижения безопасности JVM, поэтому использовать такое в нормальном окружении не стоит.
Один из мордоворотов в балахоне протянул Павлу медицинский халат, другой развязал руки.
Одевшись, Павел стал осторожно осматривать подвал в поисках пути к побегу. Но стоило его похитителям вытащить электрические дубинки и все его планы рухнули.
Павлу быстро указали направление, тыкая в него электрическими дубинками. Процессия двинулась.
Проклятый Хром
Главная проблема современного интернета и одновременно один из его столпов, текущий король клиентской части — браузер Google Chrome.
Создаваемый огромной корпорацией, этот проект постепенно выдавил практически всех конкурентов c рынка браузеров, дошло до того что даже вечный соперник в лице Microsoft стал использовать движок Chrome для своего браузера Explorer.
Фактически осталось лишь два последних конкурента:
Safari в MacOS и Firefox — два браузера, чьи движки не основаны на Chrome и развиваются независимо от него.
Думаю нетрудно догадаться, что стало происходить с Хромом, как только этот браузер занял доминирующее положение в отрасли:
его авторы начали постепенно забивать на простых пользователей.
Неотключаемый функционал, удаление или переименование опций в произвольном порядке, замалчивание проблем, откровенно черные паттерны в настройках и так далее и тому подобное.
А еще Хром стал сжирать ресурсы.
Все ресурсы, которые только есть на машине:
- GPU — для рендера CSS-стилей (я серьезно);
- Десятки отдельных процессов, не потоков — для отдельных подсистем и групп страниц;
- Аппаратные кодеки видео и аудио, жрущие как GPU так и центральный процессор;
- Встроенная поддержка DRM, убивающая вообще все, включая системные процессы браузера.
Еще там появилась совершенно отбитая внутренняя система для показа информационных баннеров о новом функционале, чтобы пользователь не заскучал.
В файле ~/.config/systemd/user создаем файл chromium.slice с вот таким содержимым:
[Slice] MemoryAccounting=true MemoryHigh=1G MemoryMax=1.5G MemorySwapMax=2G CPUAccounting=true # Weight among units in the same slice CPUWeight=50 # Maximum percentage; values above 100 indicate multiple cores CPUQuota=50%
Вот так выглядит скрипт запуска:
#!/bin/bash systemd-run --user --slice=chromium.slice chromium --disable-gpu --wm-window-animations-disabled "$@"
Visual Studio Code
Окружение пользователя
Система
В инженерном деле нет чудес и чтобы «впихнуть невпихуемое» — использовать софт, желающий всю доступную оперативную память при ее физическом отсутствии, придется эту самую память симулировать.
Используется для этих целей т.н. "своп", он же файл подкачки и как видите в моей антикварной системе, своп просто конского размера:
Как видно по скриншоту выше, я сразу понимал с кем чем имею дело, поэтому свопов два и это прям отдельные разделы на диске.
Чего советую сделать и вам, поскольку своп в виде отдельного раздела — самый производительный вариант.
Потому что это ноутбук, который временами используется "в поле", так что
Тестовый проект
https://gist.github.com/jakewarren/477ecd1149abe908cbd5cf7a7c9abaa3
https://aorith.github.io/posts/systemd-limits/
https://www.reddit.com/r/linuxquestions/comments/jfop74/how_to_use_cgroups_to_handle_badly_behaved_google/
https://alvarotrigo.com/blog/smooth-scrolling-chrome/
https://stackoverflow.com/questions/58857785/how-do-i-turn-off-the-java-language-server-in-vs-code
https://codingtechroom.com/question/prevent-vscode-reload-java-projects-startup
https://github.com/microsoft/vscode/issues/74190
https://labs.iximiuz.com/tutorials/controlling-process-resources-with-cgroups
https://gist.github.com/AssisrMatheus/678acc5a24e5c8458226000cce2309dd