lsp-mode icon indicating copy to clipboard operation
lsp-mode copied to clipboard

CPU hogs when using lsp-mode with corfu and emacs pgtk

Open nsarlin opened this issue 1 year ago • 3 comments

Thank you for the bug report

  • [x] I am using the latest version of lsp-mode related packages.
  • [x] I checked FAQ and Troubleshooting sections
  • [ ] You may also try reproduce the issue using clean environment using the following command: M-x lsp-start-plain

Bug description

Hi, first of all, thank you for the work on this great package.

I think that this is the same bug as the one reported by this issue: https://github.com/emacs-lsp/lsp-mode/issues/3720.

When I use lsp-mode with the emacs-30 branch compiled with pgtk, I get extremely frequent CPU hogs (CPU running at 100% for a few seconds) when I type code (one difference with the linked issue is that I get this with rust code).

Here is a profiler record:

        11152  91% - corfu--post-command
        11152  91%  - corfu--exhibit
        11043  90%   - corfu--update
        10891  88%    - corfu--recompute
        10891  88%     - corfu--filter-completions
        10891  88%      - completion-all-completions
        10891  88%       - completion--nth-completion
        10891  88%        - seq-some
        10891  88%         - seq-do
        10891  88%          - mapc
        10891  88%           - #<byte-code-function AC1>
        10891  88%            - #<byte-code-function AD0>
        10891  88%             - lsp-completion-passthrough-all-completions
        10891  88%              - #<byte-code-function 4B5>
        10891  88%               - #<byte-code-function 4DE>
        10888  88%                - lsp-request-while-no-input
        10888  88%                 - sit-for

I first reported it on the bug-gnu-emacs because I could not reproduce it without pgtk. However the maintainers there redirected me here, thinking that it could come from a misuse of sit-for in lsp-mode, that is only made more visible with pgtk: https://lists.gnu.org/archive/html/bug-gnu-emacs/2025-01/msg02368.html

My guess is it's this code in lsp-mode.el:

          (while (not (or resp-error resp-result (input-pending-p)))
            (catch 'lsp-done
              (sit-for
               (if expected-time (- expected-time send-time) 1)))
            (setq send-time (float-time))
            (when (and expected-time (< expected-time send-time))
              (error "Timeout while waiting for response.  Method: %s" 

method)))

This code appears to want to reliquish the CPU for the next lsp-response-timeout (default 10) seconds, so it calls sit-for with an argument close to 10.0, or 1 if no timeout is set.

The behavior of sit-for is to return immediately if there is pending input, ignoring the timeout argument.

In this case, this loop will use all of the CPU until whatever it is actually waiting for happens, assuming a single "input event" (a keypress is one, but certain kinds of mouse movement or a similar event can also cause sit-for to exit immediately) has happened.

Some other places also in that file may work less than optimally when sit-for returns immediately, also.

So this seems most likely like a bug there, and it may be triggered more by pgtk/wayland because of such details as key repeat being handled by the application rather than what used to be the X server.

Steps to reproduce

I cannot reproduce it on a small sample project, but it happens really quickly as soon as I start typing code on this project: https://github.com/zama-ai/tfhe-rs. I frequently get (every 10s typed character) emacs that freezes for a few seconds, with the process consuming 100% CPU.

My config is:

  • emacs compiled from the emacs-30 branch, with configure=--with-pgtk, running on ArchLinux with Wayland
  • lsp-mode 20250126.1915 from melpa
  • corfu 1.7 from melpa-stable

Expected behavior

No freeze

Which Language Server did you use?

rust-analyzer

OS

Linux

Error callstack

I cannot interrupt during the freeze, but I can record the following profiler report:

        11152  91% - corfu--post-command
        11152  91%  - corfu--exhibit
        11043  90%   - corfu--update
        10891  88%    - corfu--recompute
        10891  88%     - corfu--filter-completions
        10891  88%      - completion-all-completions
        10891  88%       - completion--nth-completion
        10891  88%        - seq-some
        10891  88%         - seq-do
        10891  88%          - mapc
        10891  88%           - #<byte-code-function AC1>
        10891  88%            - #<byte-code-function AD0>
        10891  88%             - lsp-completion-passthrough-all-completions
        10891  88%              - #<byte-code-function 4B5>
        10891  88%               - #<byte-code-function 4DE>
        10888  88%                - lsp-request-while-no-input
        10888  88%                 - sit-for

Anything else?

Thanks for your help! Please tell me if you need more information.

nsarlin avatar Jan 30 '25 10:01 nsarlin

Confirm! Same things happen also in my setup. Tested on large typescript projects and rust projects. As workaround switched to company-mode, which works without this issue.

acidpointer avatar Feb 02 '25 13:02 acidpointer

What's the output from the lsp logs? Have you turned on lsp-log-io and looked at the timestamps between requests and responds?

wyuenho avatar Mar 01 '25 08:03 wyuenho

I have this issue with clangd in a large project where request/response pairs can have significant (~3s) delays while the source file is being recompiled. Changing to not use corfu or eglot instead of lsp-mode makes the hangs go away.

acowley avatar Sep 30 '25 12:09 acowley