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: "stuck" at 100% CPU #34569

Open
myitcv opened this issue Sep 27, 2019 · 7 comments

Comments

@myitcv
Copy link
Member

commented Sep 27, 2019

What version of Go are you using (go version)?

$ go version
go version devel +1804bbab62 Tue Sep 24 18:20:52 2019 +0000 linux/amd64
$ go list -m golang.org/x/tools
golang.org/x/tools v0.0.0-20190926165942-a8d5d34286bd
$ go list -m golang.org/x/tools/gopls
golang.org/x/tools/gopls v0.1.8-0.20190926165942-a8d5d34286bd

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/myitcv/.cache/go-build"
GOENV="/home/myitcv/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/myitcv/gostuff"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/myitcv/gos"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/myitcv/gos/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/myitcv/gostuff/src/github.com/myitcv/govim/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build780296000=/tmp/go-build -gno-record-gcc-switches"

What did you do?

There is clearly extra CPU required with staticcheck enabled, and I see that on startup. It's just that 1 time in 5 something gets stuck

A kill -SIGABRT stack trace and gopls log file can be found here:

https://gist.github.com/myitcv/4ef84fd1115d27f1305566647278f72e

Disabling staticcheck within gopls I no longer see any problems.

What did you expect to see?

Normal operation

What did you see instead?

Per above


cc @stamblerre @ianthehat @dominikh

@mvdan

This comment has been minimized.

Copy link
Member

commented Sep 28, 2019

Did you investigate to see if it's really stuck somewhere? Maybe staticcheck is just spending a lot of time doing extra work for some reason.

@myitcv

This comment has been minimized.

Copy link
Member Author

commented Sep 28, 2019

Not looked in detail as yet. Raised the issue to see whether others are seeing problems as much as anything.

@zchee

This comment has been minimized.

Copy link
Contributor

commented Sep 28, 2019

@myitcv @mvdan I also repro this issue. I'll looking in detail soon.

@tj

This comment has been minimized.

Copy link

commented Oct 1, 2019

Not sure if I'm doing something wrong, but gopls seems to get completely stuck using %400+ CPU every few minutes for me during regular development, I have to keep killing it. I'm using golint and VSCode

@dominikh

This comment has been minimized.

Copy link
Member

commented Oct 1, 2019

What strikes me as odd are the many goroutines doing work in honnef.co/go/tools/ssa – how does gopls handle in-progress analyses when the user keeps on typing? Will only one instance of an analysis run until it finishes? Will new analyses be spawned, causing multiple instances to run at the same time?

My suspicion is that SSA construction is taking a fair amount of time, and gopls keeps spawning more of it, not waiting for completion. But that's just a guess.

@muirrn

This comment has been minimized.

Copy link

commented Oct 2, 2019

I think @dominikh is right. Every file change triggers a new diagnostics run, cancelling any previous in-progress diagnostics. As discussed in slack, the rub is that go/analysis doesn't support cancellation, so you can end up with multiple running at once. gopls has its own go/analysis driver, so it could at least check the context before starting each pass.

@myitcv myitcv changed the title x/tools/gopls: stuck at 100% CPU with staticcheck enabled x/tools/gopls: "stuck" at 100% CPU Oct 7, 2019
@myitcv

This comment has been minimized.

Copy link
Member Author

commented Oct 7, 2019

Adding my very rudimentary analysis from Slack:

So here's my current understanding after a brief analysis into why my machine was getting "hot" when gopls handled a steady stream of changes to a file:

  • the package containing the file I am changing takes ~200ms to type check
  • the analysis phase (with staticcheck turned off) takes a further ~50ms
  • the diagnostic calculations appear to run concurrently
  • it appears therefore that multiple staticcheck runs can happen simultaneously
  • there is no limit to the number of concurrent diagnostic calculations
  • there is no "collapsing" of diagnostic calculation runs - every changes triggers a recalculation of diagnostics
  • there appears to be a race whereby an earlier diagnostic run can return results after a later one

I've retitled to confirm this is not a problem with staticcheck per se. Rather that diagnostic calculations (of which staticcheck can be a part) back up after a steady stream of changes.

Could we separate the calculation of parse, type and analysis diagnostics? It seems that none of these categories should ever run concurrently in response to a change (i.e. shouldn't have two parse checks running concurrently, but ok for a parse and type check to be running concurrently), but they can (and should) run independently given the widely varying times taken to run each. Taking the example above, if staticcheck is added into the mix, the analysis phase will lengthen (significantly?). This would mean that parse errors are returned almost immediately (which is a good thing) with type errors following later, and analysis errors later still.

Thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
7 participants
You can’t perform that action at this time.