gopls version

Build info

golang.org/x/tools/gopls v0.20.0 golang.org/x/tools/gopls@v0.20.0 h1:fxOYZXKl6IsOTKIh6IgjDbIDHlr5btOtOUkrGOgFDB4= github.com/BurntSushi/toml@v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/fatih/camelcase@v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/gomodifytags@v1.17.1-0.20250423142747-f3939df9aa3c h1:dDSgAjoOMp8da3egfz0t2S+t8RGOpEmEXZubcGuc0Bg= github.com/fatih/structtag@v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fsnotify/fsnotify@v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/google/go-cmp@v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= golang.org/x/exp/typeparams@v0.0.0-20250620022241-b7579e27df2b h1:KdrhdYPDUvJTvrDK9gdjfFd6JTk8vA1WJoldYSi0kHo= golang.org/x/mod@v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= golang.org/x/sync@v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sys@v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/telemetry@v0.0.0-20250710130107-8d8967aff50b h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ= golang.org/x/text@v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= golang.org/x/tools@v0.35.1-0.20250728180453-01a3475a31bc h1:ZRKyKRJl/YEWl9ScZwd6Ua6xSt7DE6tHp1I3ucMroGM= golang.org/x/vuln@v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I= honnef.co/go/tools@v0.7.0-0.dev.0.20250523013057-bbc2f4dd71ea h1:fj8r9irJSpolAGUdZBxJIRY3lLc4jH2Dt4lwnWyWwpw= mvdan.cc/gofumpt@v0.8.0 h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k= mvdan.cc/xurls/v2@v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI= go: go1.24.3

go env

AR='ar'
CC='x86_64-pc-linux-gnu-gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='x86_64-pc-linux-gnu-g++'
GCCGO='/usr/bin/gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE=REDACTED
GOCACHEPROG=''
GODEBUG=''
GOENV=REDACTED
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build2951735111=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE=REDACTED
GONOPROXY=REDACTED
GONOSUMDB=REDACTED
GOOS='linux'
GOPATH=REDACTED
GOPRIVATE=REDACTED
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='on'
GOTELEMETRYDIR=REDACTED
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.3'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

  1. Opened delve.
  2. Typed a few letters in a test.

What did you see happen?

My CPU spiked, showing a code process taking up an excessive amount of CPU time, enough to make my fans spin up. Also error highlighting updates extremely slowly.

https://github.com/user-attachments/assets/6719c0e1-85f7-4a04-a708-c489fa12272d

What did you expect to see?

Reasonable performance.

Editor and settings

No response

Logs

I cleared the gopls log before typing and only a few characters created a 3 MB log file delve-gopls.log. It's less than 600 lines long (including empty lines) but some of those lines are absolutely massive. I believe the cause of the CPU usage spike is VSCode processing those massive events. I'm not sure what the solution is, but this is making gopls unusable. To work at any reasonable speed, I have to disable or ignore gopls, then wait a while for vscode to catch up. I'm guessing this is related to some of the recent vscode-go performance reports.

Comment From: gabyhelp

Related Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: adonovan

It looks like the main JSON blobs are inlayHints and executeCommand(gopls.packages and gopls.package_symbols). Could you try disabling inlayHints and see if that avoids the problem? That would narrow it down. Similarly, is there a way to disable the client side feature that sends each of the gopls.package{s,_symbols} requests.

Just to confirm that gopls isn't also burning CPU: could you inspect top? Alternatively, run the VS Code command "Go: Start language server's maintainer interface", which will open a browser. When the problem occurs, visit the /debug/pprof/ page and save the CPU profile that it returns after 30s.

Thanks.

Comment From: firelizzard18

Disabling the test explorer fixes the issue. It doesn't seem to matter if inlay hints are enabled or not, as long as the test explorer is disabled. I'm using my extension (Go Companion) so it should be using gopls.packages instead of the old way (asking the document symbol provider for a list of symbols and processing that in JavaScript). I'm still seeing calls to gopls.package_symbols with inlay hints and both test explorers disabled, so I'm not sure what's making that call. Though it doesn't seem to be the problem. I'll record btop in a bit.

Comment From: firelizzard18

Here's a profile and recording of btop captured (separately) while I was typing grp.SetBreakpointEnabled() like the video above. gopls certainly is consuming resources, but substantially less than code.

gopls-delve.log (actually a pprof file)

https://github.com/user-attachments/assets/c1c77015-0252-4576-bb73-a0f9534685a8

Comment From: firelizzard18

My editing experience is still not ideal, though it is substantially improved by disabling the test explorer. Disabling inlay hints does seem to make a difference in responsiveness though it's small enough that I could be tricking myself.

Simply disabling Go Companion's vscode.workspace.onDidChangeTextDocument is enough to dramatically improve responsiveness, so I'm pretty sure that's most if not all the problem there. I'm not sure what the best solution is. I can work on improving the performance of Go Companion - processing the gopls.packages response is probably a substantial part of the issue - but ultimately I think "re-query gopls for the list of tests whenever a document changes" is never going to scale well. It might be feasible to detect that I'm spending an excessive amount of time processing that event and to prompt the user to disable it. That's better than nothing but still not ideal. Ideally I could find a way to ask gopls "What changed?" but I can't immediately think of a good API for that. Is it viable for gopls to send a notification when tests are added or removed or the range of a test changes?

Comment From: firelizzard18

gopls.package_symbols is being triggered by this component:

Image

But that is debounced - the event that calls gopls.package_symbols is only triggered once I stop typing - so I don't think that's responsible for much if any lag. For now I think I'll update Go Companion to the same logic for document updates.

Comment From: firelizzard18

I updated Go Companion to be more conservative, with a setting to restore the "update as I type" behavior. Also, a notification/warning, "Hey you have this set to update as you type but those updates are taking >0.5s each so maybe you don't want to do that." That being said, a notification from gopls when tests change would still be ideal.