Skip to content

Commit 9678f79

Browse files
committed
cmd/go: work out VCS information once per repository
We need VCS status information for each main package we load. If two main packages are under the same VCS repository, we can reuse that information to avoid duplicating work. For instance, the kubernetes holds 51 main packages in its root module, meaning that "go list ./..." repeated the same git calls 51 times. Instead, use a global par.Cache to deduplicate that work. Below are the numbers on kubernetes 5eb584d1cb6917, via "benchcmd -n 8 KubernetesListPackages go list ./...": name old time/op new time/op delta KubernetesListPackages 8.91s ± 0% 3.33s ± 1% -62.61% (p=0.000 n=7+8) name old user-time/op new user-time/op delta KubernetesListPackages 11.2s ± 1% 8.1s ± 2% -27.50% (p=0.000 n=7+8) name old sys-time/op new sys-time/op delta KubernetesListPackages 8.02s ± 0% 1.67s ± 6% -79.21% (p=0.001 n=6+8) name old peak-RSS-bytes new peak-RSS-bytes delta KubernetesListPackages 127MB ± 2% 123MB ± 7% ~ (p=0.328 n=8+8) Fixes #49582. Change-Id: Ib7ef5dc7a35c83a11e209441f5d6f3b8da068259 Reviewed-on: https://go-review.googlesource.com/c/go/+/365394 Trust: Daniel Martí <[email protected]> Trust: Dominik Honnef <[email protected]> Run-TryBot: Bryan C. Mills <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent 0244343 commit 9678f79

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

src/cmd/go/internal/load/pkg.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2203,6 +2203,10 @@ func (p *Package) collectDeps() {
22032203
}
22042204
}
22052205

2206+
// vcsStatusCache maps repository directories (string)
2207+
// to their VCS information (vcsStatusError).
2208+
var vcsStatusCache par.Cache
2209+
22062210
// setBuildInfo gathers build information, formats it as a string to be
22072211
// embedded in the binary, then sets p.Internal.BuildInfo to that string.
22082212
// setBuildInfo should only be called on a main package with no errors.
@@ -2365,11 +2369,20 @@ func (p *Package) setBuildInfo() {
23652369
return
23662370
}
23672371

2368-
st, err := vcsCmd.Status(vcsCmd, repoDir)
2369-
if err != nil {
2372+
type vcsStatusError struct {
2373+
Status vcs.Status
2374+
Err error
2375+
}
2376+
cached := vcsStatusCache.Do(repoDir, func() interface{} {
2377+
st, err := vcsCmd.Status(vcsCmd, repoDir)
2378+
return vcsStatusError{st, err}
2379+
}).(vcsStatusError)
2380+
if err := cached.Err; err != nil {
23702381
setVCSError(err)
23712382
return
23722383
}
2384+
st := cached.Status
2385+
23732386
if st.Revision != "" {
23742387
appendSetting(vcsCmd.Cmd+"revision", st.Revision)
23752388
}

src/cmd/go/testdata/script/version_buildvcs_git.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ rm $GOBIN/a$GOEXE
1616

1717
# If there is a repository, but it can't be used for some reason,
1818
# there should be an error. It should hint about -buildvcs=false.
19+
# Also ensure that multiple errors are collected by "go list -e".
1920
cd ..
2021
mkdir .git
2122
env PATH=$WORK${/}fakebin${:}$oldpath
@@ -24,6 +25,10 @@ chmod 0755 $WORK/fakebin/git
2425
cd a
2526
! go install
2627
stderr '^error obtaining VCS status: exit status 1\n\tUse -buildvcs=false to disable VCS stamping.$'
28+
go list -e -f '{{.ImportPath}}: {{.Error}}' ./...
29+
stdout -count=1 '^example\.com/a: error obtaining VCS status'
30+
stdout -count=1 '^example\.com/a/library: <nil>'
31+
stdout -count=1 '^example\.com/a/othermain: error obtaining VCS status'
2732
cd ..
2833
env PATH=$oldpath
2934
rm .git
@@ -99,6 +104,14 @@ go version -m $GOBIN/d$GOEXE
99104
exec git checkout go.mod
100105
rm $GOBIN/d$GOEXE
101106

107+
# If we're loading multiple main packages,
108+
# but they share the same VCS repository,
109+
# we only need to execute VCS status commands once.
110+
go list -x ./...
111+
stdout -count=3 '^example.com'
112+
stderr -count=1 '^git status'
113+
stderr -count=1 '^git show'
114+
102115
-- $WORK/fakebin/git --
103116
#!/bin/sh
104117
exit 1
@@ -114,6 +127,12 @@ go 1.18
114127
-- repo/a/a.go --
115128
package main
116129

130+
func main() {}
131+
-- repo/a/library/f.go --
132+
package library
133+
-- repo/a/othermain/f.go --
134+
package main
135+
117136
func main() {}
118137
-- repo/b/go.mod --
119138
module example.com/b

0 commit comments

Comments
 (0)