Scrolling in switch to buffer causes extreme lag when ivy-rich-mode is on
konkrotte opened this issue · 7 comments
This is unbearable and it can cause Emacs to freeze for seconds but when I turn ivy-rich-mode off there are no lags. I am using Emacs 28.0.5 (HEAD) if that helps. Scrolling in M-x also causes lags but not nearly as severe.
Same here on Windows 10, Emacs 27 with Doom Emacs. ivy-rich
on 1097013
Its really slow when you move selection in any buffer switching
buffer, like +ivy/switch-workspace-buffer
.
For me navigating M-x
is fine.
Holding down arrow key in buffer list (~50 buffers):
- command-execute 807 94%
- call-interactively 807 94%
- funcall-interactively 807 94%
- +ivy/switch-workspace-buffer 807 94%
- +ivy--switch-buffer 807 94%
- let 807 94%
- ivy-read 807 94%
- read-from-minibuffer 805 94%
- ivy--queue-exhibit 799 93%
- ivy--exhibit 799 93%
- ivy--update-minibuffer 788 92%
- ivy--format 788 92%
- mapcar 785 91%
- ivy-rich--ivy-switch-buffer-transformer 785 91%
- ivy-rich-format 785 91%
- mapconcat 785 91%
- #<compiled 0x1857235> 785 91%
- ivy-rich-format-column 785 91%
- ivy-rich-switch-buffer-path 397 46%
- ivy-rich--switch-buffer-root-and-filename 397 46%
- ivy-rich-switch-buffer-root 397 46%
- projectile-project-root 397 46%
- cl-some 396 46%
- #<compiled 0x49258c5> 396 46%
+ file-truename 255 29%
+ projectile-root-top-down 75 8%
+ projectile-root-bottom-up 42 4%
+ projectile-root-top-down-recurring 21 2%
- ivy-rich-switch-buffer-project 366 42%
- ivy-rich-switch-buffer-root 366 42%
- projectile-project-root 364 42%
- cl-some 364 42%
- #<compiled 0x4922b6d> 364 42%
+ file-truename 237 27%
+ projectile-root-top-down 55 6%
+ projectile-root-bottom-up 53 6%
+ projectile-root-top-down-recurring 16 1%
file-remote-p 1 0%
+ ivy-rich--switch-buffer-directory 1 0%
+ +ivy-rich-buffer-icon 12 1%
+ ivy-rich-switch-buffer-indicators 2 0%
ivy-switch-buffer-transformer 1 0%
+ ivy--wnd-cands-to-str 3 0%
+ ivy--insert-minibuffer 11 1%
+ ... 41 4%
+ timer-event-handler 7 0%
EDIT: Even cycling over as few as 5 buffers introduce serious lag.
This looks familiar: doomemacs/doomemacs#1317
I am also experiencing the same lag. Based on your profiler output I think projectile-project-root
is slow, but ivy-rich-switch-buffer-project
overall is also slow (and calls projectile-project-root
multiple times). In any case, I solved this by creating a cache for the transformations (I think this method should be adopted by ivy-rich
).
(defvar ivy-rich--ivy-switch-buffer-cache
(make-hash-table :test 'equal))
(define-advice ivy-rich--ivy-switch-buffer-transformer
(:around (old-fn x) cache)
(let ((ret (gethash x ivy-rich--ivy-switch-buffer-cache)))
(unless ret
(setq ret (funcall old-fn x))
(puthash x ret ivy-rich--ivy-switch-buffer-cache))
ret))
(define-advice +ivy/switch-buffer
(:before (&rest _) ivy-rich-reset-cache)
(clrhash ivy-rich--ivy-switch-buffer-cache))
It is clearly still slow when a new candidate is shown, but it's better than nothing.
To make things even more seemless and also faster the first time switch-buffer
is called I added a timer to re-build the cache in the background when idle:
(eval-after-load 'ivy-rich
(progn
(defvar ek/ivy-rich-cache
(make-hash-table :test 'equal))
(defun ek/ivy-rich-cache-lookup (delegate candidate)
(let ((result (gethash candidate ek/ivy-rich-cache)))
(unless result
(setq result (funcall delegate candidate))
(puthash candidate result ek/ivy-rich-cache))
result))
(defun ek/ivy-rich-cache-reset ()
(clrhash ek/ivy-rich-cache))
(defun ek/ivy-rich-cache-rebuild ()
(mapc (lambda (buffer)
(ivy-rich--ivy-switch-buffer-transformer (buffer-name buffer)))
(buffer-list)))
(defun ek/ivy-rich-cache-rebuild-trigger ()
(ek/ivy-rich-cache-reset)
(run-with-idle-timer 1 nil 'ek/ivy-rich-cache-rebuild))
(advice-add 'ivy-rich--ivy-switch-buffer-transformer :around 'ek/ivy-rich-cache-lookup)
(advice-add 'ivy-switch-buffer :after 'ek/ivy-rich-cache-rebuild-trigger)))
Apologies for the noob question, but should I include both @haji-ali and @ErkiDerLoony's code in my .config file (I'm running Doom), or just @ErkiDerLoony's. Thanks.
@ErkiDerLoony’s code is enough (and more sophisticated).