CPU hogs when using lsp-mode with corfu and emacs pgtk
Thank you for the bug report
- [x] I am using the latest version of
lsp-moderelated 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.
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.
What's the output from the lsp logs? Have you turned on lsp-log-io and looked at the timestamps between requests and responds?
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.