Skip to content

Commit dfb2e42

Browse files
qiulaidongfenggopherbot
authored andcommitted
cmd/go: cache results of exec.LookPath
This CL package exec.LookPath to internal/cfg.LookPath and adds cache. BenchmarkLookPath-4 24149096 50.48 ns/op 0 B/op 0 allocs/op Fixes #36768 Change-Id: I199a780d1eab9bd5397bb3759bb42191fff716e9 Change-Id: I199a780d1eab9bd5397bb3759bb42191fff716e9 GitHub-Last-Rev: d67aa82 GitHub-Pull-Request: #61464 Reviewed-on: https://go-review.googlesource.com/c/go/+/511458 Run-TryBot: Bryan Mills <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Bryan Mills <[email protected]> Auto-Submit: Bryan Mills <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent afa3f8e commit dfb2e42

File tree

13 files changed

+61
-18
lines changed

13 files changed

+61
-18
lines changed

src/cmd/go/internal/cfg/bench_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package cfg
6+
7+
import (
8+
"internal/testenv"
9+
"testing"
10+
)
11+
12+
func BenchmarkLookPath(b *testing.B) {
13+
testenv.MustHaveExecPath(b, "go")
14+
b.ResetTimer()
15+
for i := 0; i < b.N; i++ {
16+
_, err := LookPath("go")
17+
if err != nil {
18+
b.Fatal(err)
19+
}
20+
}
21+
}

src/cmd/go/internal/cfg/cfg.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"internal/cfg"
1616
"io"
1717
"os"
18-
"os/exec"
1918
"path/filepath"
2019
"runtime"
2120
"strings"
@@ -161,7 +160,7 @@ func defaultContext() build.Context {
161160
if ctxt.CgoEnabled {
162161
if os.Getenv("CC") == "" {
163162
cc := DefaultCC(ctxt.GOOS, ctxt.GOARCH)
164-
if _, err := exec.LookPath(cc); err != nil {
163+
if _, err := LookPath(cc); err != nil {
165164
ctxt.CgoEnabled = false
166165
}
167166
}

src/cmd/go/internal/cfg/lookpath.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package cfg
6+
7+
import (
8+
"cmd/go/internal/par"
9+
"os/exec"
10+
)
11+
12+
var lookPathCache par.ErrCache[string, string]
13+
14+
// LookPath wraps exec.LookPath and caches the result
15+
// which can be called by multiple Goroutines at the same time.
16+
func LookPath(file string) (path string, err error) {
17+
return lookPathCache.Do(file,
18+
func() (string, error) {
19+
return exec.LookPath(file)
20+
})
21+
}

src/cmd/go/internal/generate/generate.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ func (g *Generator) exec(words []string) {
487487
// intends to use the same 'go' as 'go generate' itself.
488488
// Prefer to resolve the binary from GOROOT/bin, and for consistency
489489
// prefer to resolve any other commands there too.
490-
gorootBinPath, err := exec.LookPath(filepath.Join(cfg.GOROOTbin, path))
490+
gorootBinPath, err := cfg.LookPath(filepath.Join(cfg.GOROOTbin, path))
491491
if err == nil {
492492
path = gorootBinPath
493493
}

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"internal/platform"
1919
"io/fs"
2020
"os"
21-
"os/exec"
2221
pathpkg "path"
2322
"path/filepath"
2423
"runtime"
@@ -2483,7 +2482,7 @@ func (p *Package) setBuildInfo(ctx context.Context, autoVCS bool) {
24832482
goto omitVCS
24842483
}
24852484
if cfg.BuildBuildvcs == "auto" && vcsCmd != nil && vcsCmd.Cmd != "" {
2486-
if _, err := exec.LookPath(vcsCmd.Cmd); err != nil {
2485+
if _, err := cfg.LookPath(vcsCmd.Cmd); err != nil {
24872486
// We fould a repository, but the required VCS tool is not present.
24882487
// "-buildvcs=auto" means that we should silently drop the VCS metadata.
24892488
goto omitVCS

src/cmd/go/internal/script/cmds.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package script
66

77
import (
8+
"cmd/go/internal/cfg"
89
"cmd/go/internal/robustio"
910
"errors"
1011
"fmt"
@@ -824,7 +825,7 @@ func Program(name string, cancel func(*exec.Cmd) error, waitDelay time.Duration)
824825
},
825826
func(s *State, args ...string) (WaitFunc, error) {
826827
lookPathOnce.Do(func() {
827-
path, pathErr = exec.LookPath(name)
828+
path, pathErr = cfg.LookPath(name)
828829
})
829830
if pathErr != nil {
830831
return nil, pathErr

src/cmd/go/internal/script/scripttest/scripttest.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ package scripttest
77

88
import (
99
"bufio"
10+
"cmd/go/internal/cfg"
1011
"cmd/go/internal/script"
1112
"errors"
1213
"io"
13-
"os/exec"
1414
"strings"
1515
"testing"
1616
)
@@ -137,7 +137,7 @@ func CachedExec() script.Cond {
137137
return script.CachedCondition(
138138
"<suffix> names an executable in the test binary's PATH",
139139
func(name string) (bool, error) {
140-
_, err := exec.LookPath(name)
140+
_, err := cfg.LookPath(name)
141141
return err == nil, nil
142142
})
143143
}

src/cmd/go/internal/toolchain/select.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"io/fs"
1414
"log"
1515
"os"
16-
"os/exec"
1716
"path/filepath"
1817
"runtime"
1918
"strconv"
@@ -283,7 +282,7 @@ func Exec(gotoolchain string) {
283282
// Look in PATH for the toolchain before we download one.
284283
// This allows custom toolchains as well as reuse of toolchains
285284
// already installed using go install golang.org/dl/go1.2.3@latest.
286-
if exe, err := exec.LookPath(gotoolchain); err == nil {
285+
if exe, err := cfg.LookPath(gotoolchain); err == nil {
287286
execGoToolchain(gotoolchain, "", exe)
288287
}
289288

src/cmd/go/internal/vcs/vcs.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([
680680
args = args[2:]
681681
}
682682

683-
_, err := exec.LookPath(v.Cmd)
683+
_, err := cfg.LookPath(v.Cmd)
684684
if err != nil {
685685
fmt.Fprintf(os.Stderr,
686686
"go: missing %s command. See https://golang.org/s/gogetcmd\n",

src/cmd/go/internal/work/build.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"fmt"
1212
"go/build"
1313
"os"
14-
"os/exec"
1514
"path/filepath"
1615
"runtime"
1716
"strconv"
@@ -899,7 +898,7 @@ func FindExecCmd() []string {
899898
if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH {
900899
return ExecCmd
901900
}
902-
path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", cfg.Goos, cfg.Goarch))
901+
path, err := cfg.LookPath(fmt.Sprintf("go_%s_%s_exec", cfg.Goos, cfg.Goarch))
903902
if err == nil {
904903
ExecCmd = []string{path}
905904
}

src/cmd/go/internal/work/buildid.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ func (b *Builder) gccToolID(name, language string) (id, exe string, err error) {
270270
}
271271
exe = fields[0]
272272
if !strings.ContainsAny(exe, `/\`) {
273-
if lp, err := exec.LookPath(exe); err == nil {
273+
if lp, err := cfg.LookPath(exe); err == nil {
274274
exe = lp
275275
}
276276
}

src/cmd/go/internal/work/exec.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -2373,7 +2373,11 @@ func (b *Builder) runOut(a *Action, dir string, env []string, cmdargs ...any) ([
23732373
}
23742374

23752375
var buf bytes.Buffer
2376-
cmd := exec.Command(cmdline[0], cmdline[1:]...)
2376+
path, err := cfg.LookPath(cmdline[0])
2377+
if err != nil {
2378+
return nil, err
2379+
}
2380+
cmd := exec.Command(path, cmdline[1:]...)
23772381
if cmd.Path != "" {
23782382
cmd.Args[0] = cmd.Path
23792383
}
@@ -2397,7 +2401,7 @@ func (b *Builder) runOut(a *Action, dir string, env []string, cmdargs ...any) ([
23972401

23982402
cmd.Env = append(cmd.Env, env...)
23992403
start := time.Now()
2400-
err := cmd.Run()
2404+
err = cmd.Run()
24012405
if a != nil && a.json != nil {
24022406
aj := a.json
24032407
aj.Cmd = append(aj.Cmd, joinUnambiguously(cmdline))
@@ -3017,7 +3021,7 @@ func (b *Builder) gccCompilerID(compiler string) (id cache.ActionID, ok bool) {
30173021
//
30183022
// Otherwise, we compute a new validation description
30193023
// and compiler id (below).
3020-
exe, err := exec.LookPath(compiler)
3024+
exe, err := cfg.LookPath(compiler)
30213025
if err != nil {
30223026
return cache.ActionID{}, false
30233027
}

src/cmd/go/internal/work/gccgo.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func init() {
3232
if GccgoName == "" {
3333
GccgoName = "gccgo"
3434
}
35-
GccgoBin, gccgoErr = exec.LookPath(GccgoName)
35+
GccgoBin, gccgoErr = cfg.LookPath(GccgoName)
3636
}
3737

3838
func (gccgoToolchain) compiler() string {

0 commit comments

Comments
 (0)