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

godef takes ~2 seconds when used with go modules #114

ahmetb opened this issue Mar 6, 2019 · 8 comments

godef takes ~2 seconds when used with go modules #114

ahmetb opened this issue Mar 6, 2019 · 8 comments


Copy link

ahmetb commented Mar 6, 2019

godef seems to be unusually slow when used in a project using Go modules. This is making vscode-go extension slower.

Here's a repro that depends on 1 external module (and some more packages indirectly) and it takes ~1.7-3 seconds:

dir="$(mktemp -d)"

git clone "$dir"

cd "$dir"

git checkout 07cdf63

go mod download

time godef -t -f main.go -o 7099

this cursor position is a method in a directly imported package

Check func(ctx Context, in *HealthCheckRequest, opts ...CallOption) (*HealthCheckResponse, error)

godef -t -f main.go -o 7099  0.68s user 0.91s system 78% cpu 2.024 total

@rogpeppe @ianthehat

Copy link

ysoftman commented Apr 1, 2019

i had the same issue, try reinstall the godef using GO111MODULE=on environment variable.

GO111MODULE=on go get -u

Copy link

ahmetb commented Apr 1, 2019

@ysoftman I don't think your recommendation helped (in fact it made the execution time worse for some reason). Given the repro I provided above, I ran these additional commands:

rm -rf ~/go/bin/godef

GO111MODULE=on go get -u

$ which godef

time ~/go/bin/godef -t -f main.go -o 7099

the command above now takes somewhere between 3.3s and 5.5s per invocation.

Copy link

I've also seen massive latency increases on godef services since moving outside the gopath as part of the gomod update.

Copy link

Taking a quick look at this this morning (as this has also started hitting me in vscode):

  • it's specific to the new implementation that uses
  • the new implementation is used dynamically when go mod is detected, but can be forced with -new-implementation

My first run (OSX 2017 MBP) with @ahmetb's test case took 2 seconds, but subsequent runs took 0.4s, most of that in system. I haven't been able to reliably make it take multiple seconds again regardless of which offset I use.

I note that 0.3-0.5s is consistent for runs using the new implementation, whereas the old implementation is between 0.05 and 0.1s for me.

Running godef with -trace and then reading the trace shows that the 0.4s runs are spending all of their time running go itself:


Looking at the source for x/tools/packages, it looks like it's running go list. I'm not sure yet whether it's go list that is slow or whether it's the invocation of another command.

Copy link

mipearson commented Apr 17, 2019

Okay. Deleting godef and then rebuilding it with go get bumps the execution back up to 2s, which then drops to 0.7s on subsequent runs. It is definitely slower when installed using @ysoftman's suggestion.

GOMODENABLE=on go get -u

time godef -t -f main.go -o 7077 -trace trace2.out
godef -t -f main.go -o 7077 -trace trace2.out  1.90s user 0.68s system 129% cpu 1.999 total

subsequent runs:
godef -t -f main.go -o 7077 -trace trace3.out  1.24s user 0.45s system 241% cpu 0.702 total
godef -t -f main.go -o 7077 -trace trace4.out  1.26s user 0.48s system 258% cpu 0.672 total
godef -t -f main.go -o 7077 -trace trace5.out  1.26s user 0.46s system 257% cpu 0.669 total
godef -t -f main.go -o 7077  1.21s user 0.47s system 253% cpu 0.661 total
godef -t -f main.go -o 7077  1.21s user 0.46s system 262% cpu 0.635 total

go get -u

first run:
godef -t -f main.go -o 7077 -trace trace6.out  3.25s user 0.58s system 245% cpu 1.563 total

godef -t -f main.go -o 7077  0.41s user 0.34s system 205% cpu 0.367 total
godef -t -f main.go -o 7077  0.42s user 0.34s system 197% cpu 0.385 total
godef -t -f main.go -o 7077  0.42s user 0.34s system 194% cpu 0.393 total
godef -t -f main.go -o 7077 -trace trace6.out  0.43s user 0.34s system 203% cpu 0.378 total
godef -t -f main.go -o 7099 -trace trace6.out  0.43s user 0.34s system 198% cpu 0.385 total

Note that specifying -trace does not seem to affect execution time in the above measurements

Copy link


If I put grpc-health-probe in my GOPATH, then remove its go.mod/go.sum files, I get consistent < 0.1s times regardless of whether it's my first run of that godef binary or not:

within go path, go.mod/sum removed

rm ~/go/bin/godef
go get -u
# first run
godef -t -f main.go -o 7099 -trace trace.out  0.04s user 0.03s system 103% cpu 0.059 total
# subsequent
godef -t -f main.go -o 7099 -trace trace.out  0.04s user 0.03s system 97% cpu 0.073 total
godef -t -f main.go -o 7099 -trace trace.out  0.04s user 0.03s system 100% cpu 0.074 total
godef -t -f main.go -o 7099 -trace trace.out  0.03s user 0.02s system 106% cpu 0.055 total

Copy link

A half-day of deep diving later:

  1. godef uses in directories containing a go.mod to resolve things as gomodules make things non-trivial
  2. packages calls out to go list to get information about packages
  3. go list, in certain situations, will trigger a recompile of packages - this is most likely what's causing the 8-10s runs above
  4. most times go list will instead be able to use the build cache - this is where we get the 0.3s runs
  5. go list does a lot of very, very deep diving to do what it does - at a point beyond where I'm comfortable judging whether said diving is necessary for the functionality of godef or not

Looking through the traces and so forth shows lots of file opens & reads, even when the build cache is used.

My guess is that godef's original implementation could afford to be quite specialised about what it interrogated, and was thus fast. As the current implementation depends on external (and more generic purpose) tooling, that tooling could potentially be doing a lot more than it otherwise needs to be doing to get the information that godef needs.

Copy link

godef seems to speed up after running go mod vendor, I think because it doesn't have to do all the extra work🔝

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

No branches or pull requests

5 participants