May. 9th, 2025

balu: (Default)
От, власне, рік тому мене рукоположили в диякони.
balu: (Default)
Я часто використовую різні моделі Raspberry в роботі. Для багатьох задач чудовим вибором буде Raspberry Pi Zero2 — це мікрокомп’ютер розміром з половину кредитної картки. А ще я використовую Emacs. Це не просто текстовий редактор, а такий собі швейцарський ніж, який у поєднанні з практиками UNIX way надає просте та потужне середовище розробки. Тому я часто тримаю його на такого типу залізяках.

Втім, починаючи з Emacs 28, на RPi Zero2 почалися проблеми: Emacs починав страшенно гальмувати, вантажив CPU на 100% і, зрештою, наглухо підвішував пристрій. На старших моделях, а у мене RPi5, це теж відчутно, але не настільки.

Винуватцем виявився процес

emacs -no-comp-spawn -Q --batch --eval '(setq w32-disable-abort-dialog t)' -l /tmp/emacs-async-comp-org.el

Справа в тому, що ядро Emacs написане на C, а основна функціональність — на мові розширень Emacs Lisp. Так от, починаючи з версії 28, Emacs навчився компілювати lisp-код у нативний код. Щоб не витрачати час на компіляцію всього підряд, Emacs разово компіляє тільки те, що потрібно в даний момент, якщо не знаходить скомпільованих модулів. І цей процес якраз виконує цю компіляцію. У цей час у системі запущено два процеси: основний — emacs, у якому правиться код, і запущений ним процес компіляції.

Є два шляхи вирішення цієї проблеми:

1) Заборонити компіляцію в нативний код. Це робиться перед завантаженням основної конфігурації — у файлі ~/.emacs.d/early-init.el. Просто пропишіть у цьому файлі рядок:


(setq native-comp-deferred-compilation nil) ;; Вимикає автоматичну компіляцію в нативний код

і перезапустіть Emacs. Недолік цього методу в тому, що Emacs однаково компілює в байт-код — щоразу в процесі інтерпретації lisp-коду. І хоча процес компіляції в байт-код швидкий, продуктивність Emacs-а буде повільнішою, ніж у випадку з компіляцією в машинний код, що буде помітно на такій крихітці, як RPi Zero2. Тому я вирішив перейти до наступного пункту:

2) Дозволити Emacs-у скомпілювати все, що йому потрібно.
Я не знайшов нормального способу зробити це однією командою. Так, існує варіант з native-compile-async:
(mapc (lambda (dir)
         (when (file-directory-p dir)
           (native-compile-async dir 'recursively)))
       load-path)

Його можна запустити для всіх каталогів у load-path. Але це рішення мені не подобається. По-перше, воно не завжди підхоплює все потрібне, а по-друге, і це найгірше — воно компілює мої власні правки, які я часто змінюю, і я не хочу, щоб виникли розбіжності між цими правками і скомпільованим кодом. Тому я вирішив дозволити Emacs-у зробити свою справу.

Але при компіляції org-mode, який часто потрібен, Zero2 намертво зависала. Це відбувається тому, що Zero2 оснащено лише 512 MB пам’яті і, за замовчанням, лише 200 MB свопа. Як тільки компіляція вижирає всю пам’ять — Zero2 висне. Тому збільшіть розмір свопа до 1024 MB (512 буде замало) і поступово запускайте режими, які часто використовуєте, паралельно відслідковуючи завантаження процесора.

Так, я спочатку відкрив код на C — Emacs почав компілювати все, що пов’язано з цим режимом, а я дочекався, поки процеси компіляції завершаться. Потім відкрив org-файл — дочекався завершення. Потім — magit, зайшов у менеджер пакетів, почекав, поки там усе скомпілюється, далі — js-mode, python і т. ін.

Ви можете знайти скомпільоване в ~/.emacs.d/eln-cache/emacs-version/. У мене скомпільованих файлів із розширенням .eln більше 300. Якщо ви оновите якийсь пакет — Emacs перекомпіляє сам пакет і нескомпільовані залежності. Якщо оновити сам Emacs — він перекомпіляє все під нову версію.

Чи варто морочитись з компіляцією? Як на мене — так. Скомпільована в нативний код версія працює відчутно швидше та плавніше. Підгальмовування залишаються, переважно при роботі з SD-картою.

Profile

balu: (Default)
от. Михайло

May 2025

S M T W T F S
    123
45678 910
11121314151617
18192021222324
25262728293031

Style Credit

Expand Cut Tags

No cut tags
Page generated May. 21st, 2025 05:53 am
Powered by Dreamwidth Studios