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

Open
stamblerre opened this issue Jan 31, 2020 · 13 comments
Open

x/tools/gopls: reduce CPU usage #36942

stamblerre opened this issue Jan 31, 2020 · 13 comments

Comments

@stamblerre
Copy link
Contributor

@stamblerre stamblerre commented Jan 31, 2020

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
@stamblerre stamblerre removed this from the Unreleased milestone Jan 31, 2020
@stamblerre stamblerre added this to the gopls/v1.0.0 milestone Jan 31, 2020
@myitcv
Copy link
Member

@myitcv myitcv commented Jan 31, 2020

History on this in #34569

@mvdan
Copy link
Member

@mvdan 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 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 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 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.

@stamblerre stamblerre removed this from the gopls/v1.0.0 milestone Mar 12, 2020
@stamblerre stamblerre added this to the gopls/v0.6.0 milestone Mar 12, 2020
@stamblerre stamblerre removed this from the gopls/v0.6.0 milestone Apr 2, 2020
@stamblerre stamblerre added this to the gopls/v0.7.0 milestone Apr 2, 2020
@stamblerre stamblerre removed this from the gopls/v0.7.0 milestone Jun 26, 2020
@stamblerre stamblerre added this to the gopls/v0.5.0 milestone Jun 26, 2020
@stamblerre stamblerre removed this from the gopls/v0.5.0 milestone Jul 22, 2020
@stamblerre stamblerre added this to the gopls/v1.0.0 milestone Jul 22, 2020
@epelc
Copy link

@epelc epelc commented Aug 6, 2020

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

@stamblerre
Copy link
Contributor Author

@stamblerre stamblerre commented Aug 7, 2020

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

@stamblerre stamblerre commented Aug 14, 2020

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.

@hyangah hyangah moved this from Critical to Non-critical in vscode-go: gopls by default Sep 22, 2020
@stamblerre
Copy link
Contributor Author

@stamblerre 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

@gopherbot gopherbot commented Sep 25, 2020

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
@stamblerre stamblerre moved this from Non-critical to Critical in vscode-go: gopls by default Nov 10, 2020
@stamblerre stamblerre removed this from Critical in vscode-go: gopls by default Nov 18, 2020
@stamblerre stamblerre removed this from the gopls/vscode-go milestone Nov 18, 2020
@stamblerre stamblerre added this to the gopls/unplanned milestone Nov 22, 2020
@axife
Copy link

@axife 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

@stamblerre stamblerre commented Jun 4, 2021

@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 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
10 participants