go: cmd/go: `go env GOMOD` is too slow for use in interactive commands
We’re porting a lot of tools to support modules, and most of them need to know whether modules are enabled to turn on the newer, slower, potentially buggier code path. Running go env GOMOD
takes about 10ms, which is not negligible for an interactive command like godef
or guru
. The algorithm for determining if modules are on is just simple enough to tempt people to roll their own. In fact, there’s already a second implementation in go/build
: https://github.com/golang/go/blob/429bae715876c69853bb63db1733f580e293c916/src/go/build/build.go#L977
This is unfortunate, especially since the algorithm changed in http://golang.org/cl/148517. (Maybe not in a way that matters for go/build? Not sure.)
I think it’d be helpful to have a standalone internal package that implemented this functionality that could be used for go env
, go/build
, and copied into x/tools for other tools to use.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 27 (18 by maintainers)
Commits related to this issue
- internal/lazyregexp: add a lazy Regexp package This was implemented as part of go/doc, but it's going to be useful in other packages. In particular, many packages under cmd/go like web and vcs make s... — committed to golang/go by mvdan 5 years ago
- cmd/go: add benchmark that execs 'go env GOARCH' 'go env' is used for many quick operations, such as in go/packages to query GOARCH and GOMOD. It often is a bottleneck; for example, go/packages doesn... — committed to golang/go by mvdan 6 years ago
- cmd/go: avoid compiling most regexes at init These regexes are all related to commands like get and build, so they're unnecessary for simpler commands like env. In particular, we need env to be fast,... — committed to golang/go by mvdan 6 years ago
- internal/lazytemplate: add a lazy template wrapper Similar to internal/lazyregexp, this will allow removing unnecessary work from init functions with trivial refactors, thanks to sync.Once. Copy the... — committed to golang/go by mvdan 5 years ago
- cmd/go: delay parsing the testmain template The template is over a hundred lines and full of pipelines, and text/template isn't optimised to parse quickly, so it's no wonder that delaying the parsing... — committed to golang/go by mvdan 6 years ago
- errors: record only single frame See Issue #29382 and Issue #30468. 3 frames are no longer needed as of https://go-review.googlesource.com/c/go/+/152537/ name old time/op new t... — committed to golang/go by mpvl 5 years ago
- errors: improve performance of New See Issue #29382 and Issue #30468. Improvements in this CL: name old time/op new time/op delta New-8 352ns ± 2% 225ns ... — committed to golang/go by mpvl 5 years ago
- cmd/go: further reduce init work The first biggest offender was crypto/des.init at ~1%. It's cryptographically broken and the init function is relatively expensive, which is unfortunate as both crypt... — committed to golang/go by mvdan 5 years ago
I’ve found a few more ways to remove work from
cmd/go
, and nowgo env GOARCH
went from ~5ms to ~2.3ms on the added benchmark. Similarly,time go env GOARCH
has gone from ~15-20ms to ~10-12ms on my laptop, though those numbers jump around much more than the benchmark ones.I think we should be able to fairly easily shave off some more from
cmd/go
’s init for 1.13. Onperf report
,regexp.MustCompile
still owns 7%, andgo/build.init
is an astonishing 10%, so I think we could realistically shave off another 20% or even more.I’ll stop with the CLs for now, to get some input on the benchmark and style of the CLs. Happy to work on more once these have been approved.
time
reports 5-8 milliseconds to run a no-op go program on my machine, so it’s probably overhead from loading/starting the process and whatever go runtime initialization is involved.time /usr/bin/true
(an actual 17k compiled executable) takes 3-6 milliseconds on my machine so the time for the no-op go program seems reasonable to me.The algorithm has changed before, and will likely change again (whenever the default behavior switches over). Probably it’s better to make
go env GOMOD
fast than to duplicate it with version skew.I’m a total novice with the Linux
perf
tool, but it seems to imply that we’re spending a significant fraction of our latency initializing maps, regexps, and templates that aren’t actually going to be used.From
I get the following: