evil icon indicating copy to clipboard operation
evil copied to clipboard

Evil slows down org-table-align significantly

Open dinkonin opened this issue 3 years ago • 11 comments

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)

dinkonin avatar May 13 '22 07:05 dinkonin

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.

polaris64 avatar May 21 '22 17:05 polaris64

Having the same issue. Sorry be a nuisance, but any updates on this issue?

KaiAragaki avatar Jun 30 '22 04:06 KaiAragaki

No update. PR welcome

tomdl89 avatar Jun 30 '22 07:06 tomdl89

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.

KaiAragaki avatar Jul 01 '22 20:07 KaiAragaki

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.

tomdl89 avatar Jul 01 '22 20:07 tomdl89

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.

yantar92 avatar Sep 07 '22 03:09 yantar92

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.

jkuball avatar Oct 05 '22 11:10 jkuball

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.

jkuball avatar Oct 06 '22 17:10 jkuball

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.

harabat avatar Jan 05 '23 19:01 harabat

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".

haoyuan80s avatar Feb 02 '23 21:02 haoyuan80s

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

dvzubarev avatar Oct 29 '23 13:10 dvzubarev