LINUX.ORG.RU

Быстрый запуск сессии emacs desktop

 ,


1

1

Давно уже не трогал свой конфиг, но вдруг приспичило решить давнюю проблему: долгий старт emacs desktop.

У меня сессия фактически вечная, и в ней ~500 файл-буферов.
Это и на современном ПК требует минуты две, чтобы завести emacs --daemon, а на Atom Z520 все пятнадцать.

Покурил код desktop, оказывается у него есть донельзя полезная функция отложенной загрузки desktop-idle-create-buffers.

(setq desktop-restore-eager 30)  ;; restore first (last used) 30 buffers
(setq desktop-lazy-idle-delay 5)  ;; lazily restore the rest

Казалось бы, отлично: сервер подрывается с готовыми 30ю последними буферами, и тихонько грузит остаток в фоне.
Но нет, на подгружаемые таким образом буферы срабатывают все хуки и тянется это тоже вечность.

После профайла оказалось, что дохрена времени тратится на flycheck новых буферов.
Отключил его в конфиге, но оказалось у desktop нет хука по завершению desktop-idle-create-buffers.
Попробовал завернуть в defadvice, но почему-то after не срабатывает.

В результате набыдлокодил вот это:

(defvar post-init-timer nil
  "Timer used to track desktop lazy load progress")

(defun check-lazy-load-complete ()
  "Check if desktop finished resurrecting all buffers"
  (if (not desktop-buffer-args-list) (desktop-full-lazy-load-complete)))

(defun desktop-full-lazy-load-complete ()
  "Hook function executed after desktop lazy load is completed"
  (cancel-timer post-init-timer)  ;; stop timer
  (message "Emacs ready in %s with %d garbage collections."
           (format "%.2f seconds"
                   (float-time
                    (time-subtract (current-time) before-init-time)))
           gcs-done)
  ;; Return to defaults after startup
  (setq gc-cons-threshold gc-cons-threshold-original)
  (setq gc-cons-percentage gc-cons-percentage-original)
  ;; Don’t compact font caches during GC.
  (setq inhibit-compacting-font-caches t)  ;; Emacs 25.2 or later
  (global-flycheck-mode t)
  (garbage-collect))

(setq post-init-timer (run-with-timer 60 5 'check-lazy-load-complete))


В начале конфига, соответственно:
;;; Call GC only once per 500M words (500Mb on x86 and 1000Mb on amd64) of allocations
(setq gc-cons-threshold-original gc-cons-threshold)  ;; save defaults
(setq gc-cons-percentage-original gc-cons-percentage)  ;; save defaults
(setq gc-cons-threshold 524288000)
(setq gc-cons-percentage 10)


Что имеем: за несколько секунд подрывается сервер с 30ю последними буферами и сразу доступен.
Дальше без перерывов на сборку мусора и флайчек подсасываем остальные полтыщи.
После чего включается флайчек и возвращаются стандартные настройки сборщика.

В сухом остатке многострадальный Atom Z520 заливает в себя полную сессию всего за 4 минуты, а доступен практически сразу, вместо 15и минут медитации.

Успех.

P.S. как истинный емаксер елиспа я до сих пор не знаю.

★★★★★

Отключил его в конфиге, но оказалось у desktop нет хука по завершению desktop-idle-create-buffers.

Вообще, хук такой как бы есть — desktop-delay-hook (Documentation string: Hooks run after all buffers are loaded; intended for internal use.). Хук по завершению ленивой загрузки буферов, так? Интересно, почему его в пользовательский интерфейс не вывели? Может, он подойдет?

Он только после run-hooks всегда устанавливается в nil (это я по исходникам смотрю).

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)

Я бегло глянул - напрямую ему add-hook делать не стоит, так как он при вызове desktop-read принудительно зануляется, поэтому все, что будет в нем присвоено, затрется. Но зато после его начального затирания вызывается хук desktop-after-read-hook, в котором уже можно попробовать сделать (add-hook 'desktop-delay-hook ...). Может, что-то выйдет. Чтобы сказать точно, надо внимательнее исходник поглядеть. Ну, сам погляди.

Zubok ★★★★★
()

На мелком оборудовании я использую дефолт с минимумом исправлений )) Ну и, конечно, «слепой набор».

n1rdeks
()

После профайла оказалось, что дохрена времени тратится на flycheck новых буферов.

Во-во.

n1rdeks
()
Ответ на: комментарий от Zubok

desktop-delay-hook просто неверно описан в докстринге: он дёргается после каждого lazy-create-buffer.

desktop-after-read-hook дергается после первого рывка restore-eager и всё.

Вот почему defadvice after desktop-idle-create-buffers не вызывается вообще - я хз.
Поэтому и костыль с таймером и чеком очереди на восстановление.

aidaho ★★★★★
() автор топика
Ответ на: комментарий от aidaho

desktop-delay-hook просто неверно описан в докстринге: он дёргается после каждого lazy-create-buffer.

Ага, увидел.

Нет, он верно, наверное, описан, но для случая, когда нет lazy, то есть без ленивой загрузки. Я опять же бегло глянул. А вот именно в случае ленивой загрузки - на каждый буфер.

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)
Ответ на: комментарий от aidaho

А что если в desktop-delay-hook проверять desktop-buffer-args-list? Как только пуст, то, значит, это был последний буфер. Но хук этот неприятный в том смысле, что он описан, как internal use.

UPD. Хотя нет. Он каждый раз в nil инициализируется после вызова. Говно.

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)

дохрена времени тратится на flycheck новых буферов

Я просто выключил flycheck при включении, оставил только при сохранении буфера.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Тоже вариант, но неудобно, если надо посмотреть чужую работу.
Я себе оставил

(setq flycheck-check-syntax-automatically '(save idle-change mode-enabled))

А то он вообще после каждого newline хочет запускаться, что совсем уже перебор.

Так то я в рамках субботнего красноглазия ещё на модно-молодёжный lsp-mode хотел переползти, но кровь начала хлестать из глазниц от визуальной цветомузыки ворнингов, дефинишенов, вхождений и докстрингов.

Оказалось, это сделали в MSVS, что очень многое сразу объяснило.

aidaho ★★★★★
() автор топика
Последнее исправление: aidaho (всего исправлений: 1)
Ответ на: комментарий от aidaho

По таймеру проверять загрузку, конечно, вариант, но такой... немного коробит.

Как вариант: может быть повесить проверку desktop-buffer-args-list в хуке в момент создания нового буфера? То есть при создании нового буфера в хуке проверяется этот список. Как только стал пуст, то это был последний буфер, хук можно удалить и запускать flycheck.

Какой хук лучше, зависит от желания и что подойдет. Можно after-change-major-mode-hook или buffer-list-update-hook. Инициализировать этот хук можно в хуке desktop-after-read-hook, то есть если кто-то вызвал восстановление desktop, то следить за списком desktop-buffer-args-list. Стал пустым - хук удалить. Так получится как бы без таймера.

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)
Ответ на: комментарий от Zubok

Можно и так. Но прям особого смысла нет по моему.
desktop одним таймером восстанавливает буферы, я за ним приглядываю другим.

И то и то костыльно, и должно быть по уму решено в desktop.
В специальной олимпиаде на «чистоту» этих решений мне кажется победителей нет.
Мой быдло-хук в ходе четырёхминутного старта будет дёрнут 36 раз, а буфер-хук полтыщи.
Это всё семечки конечно.

Лучше всего бы им патч заслать, но говорят у них кровью на пулл-реквесте расписываться надо.

P.S. попробовал ещё раз набросать эдвайс. В этот раз работает.
Не знаю, что я в прошлый раз не так написал.
Но вызывается после каждого срабатывания idle-timer.
Что в общем логично, но в этих лиспах всяко могло быть.

aidaho ★★★★★
() автор топика
Ответ на: комментарий от aidaho

на модно-молодёжный lsp-mode хотел переползти

Я на днях обратно с него переполз, ибо оно жрёт проц как не в себя. Видимо оно не приспособлено для over100500 буферов одновременно.

no-such-file ★★★★★
()
Ответ на: комментарий от aidaho

Тут все костыли хотя бы в том смысле, что делается попытка использовать переменные или функции, которые либо по недосмотру, либо изначально не предполагаются для легального использования пользователем. Они нигде не описаны в документации, они отсутствуют в customization. Тут: использование списка desktop-buffer-args-list, смысл которого ясен из анализа исходников, но который нигде не описан; тут же и функция desktop-idle-create-buffers, которая тоже нигде не описана - ни в Emacs Manual, ни в Elisp Manual, ни в главном заголовке в исходном коде. В этом смыcле, да, всё костыли.

Мой быдло-хук в ходе четырёхминутного старта будет дёрнут 36 раз, а буфер-хук полтыщи. Это всё семечки конечно.

Ну, да. Это микроскопическое, даже наноскопическое действие по сравнению с тем, что происходит, когда выполняется открытие буфера и инициализация major-mode. Семечки.

Лучше всего бы им патч заслать, но говорят у них кровью на пулл-реквесте расписываться надо.

Я когда-то подсуетился и расписался кровью. Подписал бумажный договор о передаче прав FSF на код в проектах Emacs и ELPA. Иначе патчи не примут.

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)
Ответ на: комментарий от Zubok

Я когда-то подсуетился и расписался кровью. Подписал бумажный договор о передаче прав FSF на код в проектах Emacs и ELPA. Иначе патчи не примут.

А код расписавшимся дарить можно? Чтобы они передарили FSF?

aidaho ★★★★★
() автор топика
Ответ на: комментарий от aidaho

В договоре есть пункт, в котором разработчик заявляет, что является единственным владельцем прав на код, права на который он передает FSF. Поэтому должна быть процедура передачи прав от третьего лица разработчику, которая соответствует всем формальностям, устраивающим FSF. Наверное, так. Но я не знаю, чего достаточно. Если будут претензии от третьей стороны внезапно, то, во-первых, код, наверное, удалят, чтобы от греха подальше, и также это нанесет вред репутации разработчика, во-вторых.

Но это так себе проблема. Большая проблема в том, что за чужой код будет нести ответственность разработчик. Ему будут задавать вопросы, просить что-то исправить. то есть простой коммит для разработчика превратится в разбирательства с чужим кодом и отстаивание в рассылке чужих идей (ну, только если вы не одним проектом совместно занимаетесь). В твоем случае надо не только код дописывать, но и в документации на Elisp все это отразить.

Zubok ★★★★★
()

На хрена это мозгосношение если можно просто стартануть демон емакса как пользовательский сервис systemd? Он загрузится вместе с десктоп сессией и потом emacsclient будет работать практически мнгновенно.

zabbal ★★★★★
()
Ответ на: комментарий от zabbal

мозгосношение
стартануть демон емакса как пользовательский сервис systemd

А ты забавный.

aidaho ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.