Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/tools/gopls: reduce CPU usage #36942

Closed
stamblerre opened this issue Jan 31, 2020 · 14 comments
Closed

x/tools/gopls: reduce CPU usage #36942

stamblerre opened this issue Jan 31, 2020 · 14 comments
Labels
FrozenDueToAge gopls/performance Issues related to gopls performance (CPU, memory, etc). gopls Issues related to the Go language server, gopls. Thinking Tools This label describes issues relating to any tools in the x/tools repository.

Comments

@stamblerre
Copy link
Contributor

gopls hogs the user's CPU when they are typing quickly, as it starts type-checking on every keystroke. We should debounce requests or otherwise reduce the frequency of type-checking as a user is editing their file.

@gopherbot gopherbot added this to the Unreleased milestone Jan 31, 2020
@gopherbot gopherbot added Tools This label describes issues relating to any tools in the x/tools repository. gopls Issues related to the Go language server, gopls. labels Jan 31, 2020
@stamblerre stamblerre modified the milestones: Unreleased, gopls/v1.0.0 Jan 31, 2020
@myitcv
Copy link
Member

myitcv commented Jan 31, 2020

History on this in #34569

@mvdan
Copy link
Member

mvdan commented Feb 1, 2020

You could also be a bit smarter about what characters the user is typing. If the user is in the middle of typing an identifier or a string, it's unlikely that typechecking at every keystroke is going to be useful. However, if right after an identifier they type . or :, it's likely that an incremental typecheck would add useful information.

This doesn't have to be a binary decision, though. There could be a heuristic based on the time between keystrokes and the characters being typed, for example.

@myitcv
Copy link
Member

myitcv commented Feb 1, 2020

Just to also note that I'm particularly seeing issues when govim starts in a medium-large project. gopls is so efficient at using all CPU power available, that the initial load makes my machine unusable. Whilst this cost will be amortised by #34111, the initial load for any project should probably max out at ~50% available CPU (just to pluck a figure from thin air)

@muirdm
Copy link

muirdm commented Feb 2, 2020

I imagine we are going to end up with two type checking modes. We will have the heavily debounced (~500ms) full type checking for diagnostics, and we will have the tricksy minimal type checking used for synchronous operations like completion. The three main minimal type checking tricks I've seen discussed are:

  1. Don't type check func bodies except the one containing the cursor.
  2. Don't type check at all for edits that merely extend an identifer/string/comment (as suggested above by @mvdan).
  3. Use types.CheckExpr to incrementally type check the expression/statement containing the cursor.
  1. is probably the hardest and would provide limited benefit assuming 1) and 2) are implemented.

@dominikh
Copy link
Member

dominikh commented Feb 3, 2020

I would even argue that not all diagnostics should run at the same rate (say, muir's 500ms). Some analyses (particularly in staticcheck) are much more expensive than others, and also point out larger bugs than what can be affected by typing 5 characters. A simple differentiator could be those analyses that work purely on the AST, and those that rely on an IR (go/ssa, staticcheck's IR). Building the IR form is an expensive operation.

@epelc
Copy link

epelc commented Aug 6, 2020

Is there potential to only run on save instead of on keystroke?

@stamblerre
Copy link
Contributor Author

No, the model of gopls is such that changes have to be processed on every keystroke (for other features to work correctly).

@stamblerre
Copy link
Contributor Author

Writing this down to make a note of it: @heschik and I discussed continuously profiling gopls, reading the protos, and writing them out to a temporary file if CPU usage exceeds some limit (much like @heschik did for memory usage). We're not sure if this will provide more useful information past what we already know (that type-checking and analysis can cause a lot of CPU utilization), but this will be helpful when users report CPU utilization issues.

@stamblerre
Copy link
Contributor Author

stamblerre commented Sep 25, 2020

Some additional ideas that came out of today's meeting:

Before v1.0

Separate diagnostic publication for the package of the file being modified from diagnostic publication for other packages in the workspace. This will reduce the appearance of the latency of diagnostics as you code, and it will allow us to debounce the diagnostics only for the other packages, which could reduce CPU usage.

After v1.0

Separate diagnostic publication for parse / type-check / analysis errors. This will allow us to debounce type-checking and analysis diagnostics without affecting the latency of parse diagnostics. The only complication here is that this will change our diagnostic caching model, unless microsoft/language-server-protocol#1088 is resolved before we implement this.

@gopherbot
Copy link
Contributor

Change https://golang.org/cl/257378 mentions this issue: internal/lsp: publish diagnostic reports for "relevant" files earlier

@golang golang deleted a comment from gopherbot Sep 25, 2020
@axife
Copy link

axife commented Jun 3, 2021

I do not consider cpu load on key stroke an issue. But I start experience constant cpu load when I do nothing. If I restart VSCode then load is 0%after some time like an hour or so it starts consume CPU again and I have restart again.

@stamblerre
Copy link
Contributor Author

@axife: Please file a separate issue with more concrete details if you have a CPU-related problem to report.
You can find the gopls troubleshooting guide here.

@pcj
Copy link

pcj commented Oct 8, 2021

What is it about gopls that is so CPU intensive anyhow? I don't even know where to start, but every time I try and run it, I can't have my laptop in, well, my lap. I have to have a pillow or something to insulate me from the heat that my CPU emits. Here's a typical look where it's using up 50% of my CPU when I'm not even typing, and it seems to not be able to get itself out of this state without restarting gopls, and then I have maybe another 10min or so before it starts burning a new hole in my clothes.

>49.8  3.3   5.86G 1.04G 82715 paul.john     27:09 24    0 R /Users/paul.johnston/go/bin/gopls -mode=stdio -rpc.trace

@findleyr findleyr added gopls/performance Issues related to gopls performance (CPU, memory, etc). and removed Performance labels Oct 8, 2021
@adonovan
Copy link
Member

adonovan commented Apr 23, 2023

The CPU costs of the initial workspace load and the per-keystroke reactive work should now both be dramatically reduced at master, and in the upcoming v0.12.0 release. Closing this now.

@golang golang locked and limited conversation to collaborators Apr 22, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge gopls/performance Issues related to gopls performance (CPU, memory, etc). gopls Issues related to the Go language server, gopls. Thinking Tools This label describes issues relating to any tools in the x/tools repository.
Projects
None yet
Development

No branches or pull requests