Evil slows down org-table-align significantly
Issue type
- Bug report
Environment
Emacs version: GNU Emacs 28.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.33, cairo version 1.17.6)
Operating System: Archlinux
Evil version: 1.15.0
Evil installation type: manual
Graphical/Terminal: Graphical
Tested in a make emacs session No
Reproduction steps
Open on a large orgmode table with long columns with evil-enabled in an emacs -Q session, choose a column and do M-x org-table-delete-column:
Expected behavior
It takes 2 seconds to complete (with a fairly large table) without (require 'evil) (evil-mode 1)
Actual behavior
When I enable evil it takes 8-10 seconds
Further notes
Profiler output WITH evil enabled:
6722 100% - command-execute
6145 91% - funcall-interactively
6145 91% - execute-extended-command
6145 91% - command-execute
6145 91% - funcall-interactively
6126 91% - org-table-delete-column
5922 88% - org-table-align
4024 59% - cl-mapcar
4020 59% - cl--mapcar-many
4017 59% - org-table--align-field
3905 58% - org-string-width
3748 55% - set-window-buffer
3745 55% - apply
3742 55% - ad-Advice-set-window-buffer
3717 55% - evil-local-mode
3200 47% - add-hook
3197 47% - #<compiled 0x1afd915d64e7724e>
407 6% alist-get
494 7% + evil-initialize-state
4 0% evil--jumps-install-or-uninstall
22 0% + #<subr set-window-buffer>
129 1% + #<compiled -0x1c88ca61cb76bc97>
8 0% + version<
1728 25% + org-string-width
56 0% + org-font-lock-ensure
71 1% + org-fold-core--fix-folded-region
35 0% + org-element--cache-after-change
30 0% + org-at-table-p
8 0% + jit-lock-after-change
577 8% + byte-code
Profiler output WITHOUT evil enabled:
1323 65% - timer-event-handler
1323 65% + apply
530 26% - command-execute
413 20% - funcall-interactively
413 20% - execute-extended-command
413 20% - command-execute
413 20% - funcall-interactively
392 19% - org-table-delete-column
342 17% - org-table-align
160 7% + #<compiled -0x222b0ce9fbbe5dc>
117 5% + org-font-lock-ensure
18 0% + jit-lock-after-change
11 0% + org-string-width
10 0% + cl-mapcar
16 0% + org-at-table-p
4 0% org-table-goto-column
117 5% + byte-code
146 7% + ...
7 0% + redisplay_internal (C function)
I just came across this exact bug too. My profiler reports look very similar to those that you posted above, so I have no more technical detail to add. If I get time I will try to bisect evil mode to see if I can find where this issue was introduced.
Having the same issue. Sorry be a nuisance, but any updates on this issue?
No update. PR welcome
Can't help via PR (too dumb) but can say that this appears to occur on 28.1 (Mint OS) but not 27.2 (MacOS), using the latest version of evil in both cases.
You could always try bisecting evil to pinpoint the offending commit. Although bisecting Emacs sounds like a good idea too. Just something I don't have the time/inclination to look into right now.
The offending code is https://github.com/emacs-evil/evil/blob/b47cb64ceb6d10ecc4a132dce8e3ac0465e1b637/evil-core.el#L368. org-string-width uses set-window-buffer to calculate precise string width (similar to shr-pixel-column). Unlike the comment in the evil code assumes, it is still done in a throwaway buffer.
Not really a solution but at least a feasible workaround: You can toggle evil-mode with C-z and then edit the tables freely using emacs keybinds. At least for me it is way faster to do so.
Edit: I sadly have to take that back. It worked once for me to reapply formulas fast, but now it is back to slowing everything down. It seems to help a little, but that also can be placebo.
A more sophisticated workaround is to comment the code block @yantar92 mentioned above. I will probably find some buffers where evil mode won't be activated, but it works for my org files right now.
Edit: Sorry for my monologue, I am just writing down my thoughts and findings. Sadly after using it a little bit with commented code I still feel like there is another culprit. It was fast at first for the first few rows I added, but now it is back to being slow for every time the editor leaves evil insert mode (including using x and r). Also, I am not talking about big complex tables, I just have like 100 rows and 5 columns without any formulas.
Edit 2: I am not sure whether my commenting worked at all. I am not that familiar with the internals of emacs, I am just trying out doom for quite some time now. But I have some more intel: After restarting emacs and reopening only my org file with the table in it, it works for like two to three edits, then it starts to get slow. Watching the activity monitor it seems like Emacs is using more and more RAM. Might be some kind of memory leak (but it is not that hard, I am talking about 2-4 MB more before it starts to get slow). Right now it is 18 MB above the start and working with the table is unbearable.
I'm pasting a different CPU profiler output that includes a few more evil-local-mode sub-items, in case this helps pinpoint the issue: https://pastebin.com/n3rfXpRz
CPU profiler output narrowed down to `org-table-align`
8907 86% - org-table-align
4359 42% - org-string-width
3829 37% - set-window-buffer
3826 37% - apply
3826 37% - ad-Advice-set-window-buffer
3647 35% - evil-local-mode
1402 13% - add-hook
1402 13% - #<compiled 0x1589db20cd0d724e>
163 1% alist-get
1225 11% - evil--jumps-install-or-uninstall
1222 11% - add-hook
1222 11% - #<compiled 0x1589db20cd0d724e>
204 1% alist-get
992 9% - evil-initialize-state
989 9% - evil-change-to-initial-state
942 9% - evil-change-state
942 9% - evil-normal-state
667 6% - add-hook
667 6% - #<compiled 0x1589db20cd0d724e>
119 1% alist-get
212 2% - evil-normalize-keymaps
174 1% + evil-state-keymaps
14 0% + evil-refresh-cursor
3 0% evil-refresh-mode-line
41 0% + evil-initial-state-for-buffer
6 0% + evil-disabled-buffer-p
4 0% + evil-concat-lists
162 1% + #<subr set-window-buffer>
506 4% + #<compiled -0x1c8a0cbdf1e67697>
14 0% version<
4201 40% - cl-mapcar
4201 40% - cl--mapcar-many
4194 40% - org-table--align-field
4151 40% - org-string-width
3550 34% - set-window-buffer
3550 34% - apply
3550 34% - ad-Advice-set-window-buffer
3435 33% - evil-local-mode
1268 12% - add-hook
1268 12% + #<compiled 0x1589db20cd0d724e>
1265 12% - evil--jumps-install-or-uninstall
1261 12% - add-hook
1261 12% - #<compiled 0x1589db20cd0d724e>
267 2% alist-get
870 8% - evil-initialize-state
870 8% - evil-change-to-initial-state
812 7% - evil-change-state
806 7% - evil-normal-state
578 5% - add-hook
578 5% - #<compiled 0x1589db20cd0d724e>
156 1% alist-get
198 1% + evil-normalize-keymaps
6 0% + evil-refresh-cursor
51 0% + evil-initial-state-for-buffer
4 0% + evil-concat-lists
3 0% + evil-disabled-buffer-p
109 1% + #<subr set-window-buffer>
562 5% + #<compiled -0x1c8a0c0a29a87097>
20 0% version<
215 2% + font-lock-ensure
36 0% + #<compiled -0x222b0afd8ec599c>
7 0% + org-fold-core--fix-folded-region
6 0% org-indent-notify-modified-headline
4 0% ws-butler-after-change
4 0% org-element--cache-after-change
3 0% org-indent-refresh-maybe
System: Manjaro, https://github.com/doomemacs/doomemacs/commit/e96624926d724aff98e862221422cd7124a99c19
I'll try bisecting Doom to add further details when I find the time.
I also met this slow down issue. I remove the advice "ad-Advice-set-window-buffer" as:
(advice-remove 'set-window-buffer #'ad-Advice-set-window-buffer)
Now, it is fast again, but I am not sure what is the disadvantage of "hack".
I think it is fixed with new versions of Org and Emacs. It takes no time to realign a large table (170x10). Emacs 29.1 Org mode version 9.7