Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scrolling in switch to buffer causes extreme lag when ivy-rich-mode is on #87

Open
konkrotte opened this issue Jul 7, 2020 · 7 comments

Comments

@konkrotte
Copy link

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.

@EtiamNullam
Copy link

EtiamNullam commented Jul 17, 2020

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.

@EtiamNullam
Copy link

This looks familiar: doomemacs/doomemacs#1317

@haji-ali
Copy link

haji-ali commented Sep 9, 2020

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.

@ErkiDerLoony
Copy link

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)))

@arozbiz
Copy link

arozbiz commented Jan 26, 2021

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.

@haji-ali
Copy link

@ErkiDerLoony’s code is enough (and more sophisticated).

@arozbiz
Copy link

arozbiz commented Jan 26, 2021 via email

dmacvicar added a commit to dmacvicar/dotfiles that referenced this issue Feb 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants