Subject: bug#66512: 30.0.50; flymake with checkdoc slows down typing in large Elisp buffers

From: Visuwesh <[email-masked]>
Date: Sat, 14 Oct 2023 14:59:29 +0530

[வெள்ளி அக்டோபர் 13, 2023] Eli Zaretskii wrote:

>> From: Visuwesh <[email-masked]>
>> Date: Fri, 13 Oct 2023 11:23:31 +0530
>> 
>> flymake-mode is largely unusable in large Elisp buffers with checkdoc
>> enabled as it sometimes takes a second for the typed words to be
>> displayed, and there are too many micro freezes.  I have attached two
>> profiles one from emacs -Q, and one from my personal configuration saved
>> using the command profiler-report-write-profile.  Both point to
>> checkdoc-this-string-valid being the time consuming function.
>> 
>> To reproduce,
>> 
>>     1. src/emacs -Q
>>     2. C-x C-f lisp/org/org.el RET
>>     3. M-x flymake-mode RET
>>     4. M-g i org-drag-line-forward RET
>>     5. Move the point to be inside the docstring, and start typing away.
>>        You should notice the latency sooner or later.
>> 
>> I can reproduce this in my fairly long init.el file too (~10k lines) and
>> I was forced to turn off checkdoc for the typing to be bearable in my
>> init.el file.
>
> Thanks.
>
> This report needs more info:
>
>   . the file you used which produces this slowdown

I used org.el in the example.

>   . the profile is not fully expanded (some functions have "+")
>   . for more detailed profile, please load the relevant Lisp files as
>     *.el (not *.elc), and repeat the profiling
>   . if the slowdown is visible in "emacs -Q", the profile from that is
>     more important than the one from your customized Emacs

Here's the fully expanded profile after evaluating the checkdoc.el
library in emacs -Q.  I also attached the file written by
profiler-report-write-profile too.

There are still a couple compiled functions but I think they are safe to
ignore for now.

        3260  67% - timer-event-handler
        3260  67%  - apply
        3260  67%   - #<compiled 0x1f6faae8cb95a424>
        3260  67%    - flymake-start
        3260  67%     - run-hook-wrapped
        3260  67%      - #<compiled -0x280737ed0d75cb0>
        3260  67%       - flymake--run-backend
        3260  67%        - apply
        3239  67%         - elisp-flymake-checkdoc
        3231  67%          - checkdoc-current-buffer
        3231  67%           - let
        3231  67%            - or
        2655  55%             - checkdoc-start
        2655  55%              - let
        2655  55%               - checkdoc-continue
        2655  55%                - let
        2655  55%                 - save-excursion
        2655  55%                  - while
        2037  42%                   - setq
        2037  42%                    - checkdoc-this-string-valid
        2033  42%                     - let
        1123  23%                      - if
        1123  23%                       - let
        1115  23%                        - unwind-protect
        1115  23%                         - progn
        1115  23%                          - checkdoc-this-string-valid-engine
        1115  23%                           - let
        1103  22%                            - or
         699  14%                             - save-excursion
         348   7%                              - let*
         252   5%                               - while
         248   5%                                - and
         244   5%                                 - or
         244   5%                                  - progn
         224   4%                                   - <
         220   4%                                      current-column
           4   0%                                      funcall
          20   0%                                     end-of-line
           4   0%                                 - <
           4   0%                                    point
           4   0%                                  forward-line
          84   1%                               - function
          84   1%                                - cconv-make-interpreted-closure
          44   0%                                 - cconv-fv
          36   0%                                  - cconv-analyze-form
          28   0%                                   - cconv--analyze-function
           8   0%                                    - cconv-analyze-form
           4   0%                                     - #<compiled 0x1e3233529d73ee4f>
           4   0%                                        cconv-analyze-form
           4   0%                                    - mapcar
           4   0%                                       #<compiled -0x1ee9fee790b185f2>
           4   0%                                    make-closure
          32   0%                                 - macroexpand-all
          28   0%                                  - macroexp--expand-all
          24   0%                                   - macroexp--all-forms
          20   0%                                    - macroexp--expand-all
          20   0%                                     - #<compiled 0x19f73f8625989308>
           8   0%                                      - macroexp--all-forms
           4   0%                                         macroexp--expand-all
           8   0%                                      - function-get
           4   0%                                         fboundp
           4   0%                                 end-of-line
         307   6%                              - let
         307   6%                               - while
         179   3%                                - and
         135   2%                                   re-search-forward
          44   0%                                 + setq
         108   2%                                + if
          12   0%                                + let*
           8   0%                                + setq
          20   0%                              + if
           8   0%                              + cond
           4   0%                                skip-chars-backward
           4   0%                                beginning-of-line
           4   0%                                forward-line
         172   3%                             + cond
         104   2%                             + checkdoc-sentencespace-region-engine
          76   1%                             + checkdoc-proper-noun-region-engine
          36   0%                             + let
           8   0%                               checkdoc-ispell-docstring-engine
           8   0%                             + if
          12   0%                            + if
           4   0%                          syntax-table
         910  18%                      + checkdoc-defun-info
           4   0%                     + while
         618  12%                   + and
         304   6%             + checkdoc-rogue-spaces
         272   5%             + checkdoc-message-text
           8   0%          - #<compiled 0x1f518ae41b6bfdca>
           8   0%           - apply
           8   0%            - flymake--handle-report
           8   0%             - flymake--publish-diagnostics
           4   0%              - flymake--highlight-line
           4   0%                 #<compiled 0x45577ddd5ec64ee>
           4   0%              - flymake--delete-overlay
           4   0%                 delete-overlay
          21   0%         - elisp-flymake-byte-compile
          21   0%            write-region
        1324  27%   Automatic GC
         146   3% - redisplay_internal (C function)
          17   0%  - jit-lock-function
          17   0%   - jit-lock-fontify-now
          17   0%    - jit-lock--run-functions
          17   0%     - run-hook-wrapped
          17   0%      - #<compiled -0x72b32c146f17ee7>
          17   0%       + font-lock-fontify-region
           8   0%  - eval
           4   0%   - flymake--mode-line-counter
           4   0%    - flymake--mode-line-counter-1
           4   0%     - flymake--severity
           4   0%      - flymake--lookup-type-property
           4   0%         plist-member
           4   0%   - flymake--mode-line-title
           4   0%      make-sparse-keymap
           1   0%  - redisplay--pre-redisplay-functions
           1   0%     run-hook-with-args
           1   0%  - file-remote-p
           1   0%     find-file-name-handler
          72   1% - command-execute
          72   1%  - call-interactively
          65   1%   - byte-code
          65   1%    - read-extended-command
          65   1%     - read-extended-command-1
          65   1%      - completing-read
          65   1%       - completing-read-default
          65   1%        - read-from-minibuffer
          25   0%           redisplay_internal (C function)
          10   0%         - timer-event-handler
          10   0%          - apply
          10   0%           - #<compiled 0x1f6faae8cb95a424>
          10   0%            - flymake-start
          10   0%             - run-hook-wrapped
          10   0%              - #<compiled -0x286221700d75cb0>
          10   0%               - flymake--run-backend
          10   0%                - apply
          10   0%                 - elisp-flymake-byte-compile
          10   0%                  - write-region
           4   0%                   - make-lock-file-name
           4   0%                      find-file-name-handler
           7   0%   + funcall-interactively
           9   0% - #<compiled 0x9076c9ab87f5262>
           9   0%  - flymake--log-1
           9   0%   - display-warning
           9   0%    - icon-string
           9   0%     - icons--create
           9   0%      - apply
           9   0%       - #<compiled 0x1960f398ac366a51>
           9   0%          internal-char-font
           7   0% - clear-minibuffer-message
           7   0%    timerp
           2   0% - jit-lock--antiblink-post-command
           2   0%  - syntax-ppss
           2   0%   - syntax-propertize
           2   0%      make-local-variable
           0   0%   ...