]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: cache results of exec.LookPath
authorqiulaidongfeng <2645477756@qq.com>
Sat, 9 Sep 2023 00:58:21 +0000 (00:58 +0000)
committerGopher Robot <gobot@golang.org>
Mon, 11 Sep 2023 20:12:18 +0000 (20:12 +0000)
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: d67aa826f431affe829c23d1fdf2241fbb611303
GitHub-Pull-Request: golang/go#61464
Reviewed-on: https://go-review.googlesource.com/c/go/+/511458
Run-TryBot: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
Auto-Submit: Bryan Mills <bcmills@google.com>
Reviewed-by: Heschi Kreinick <heschi@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

13 files changed:
src/cmd/go/internal/cfg/bench_test.go [new file with mode: 0644]
src/cmd/go/internal/cfg/cfg.go
src/cmd/go/internal/cfg/lookpath.go [new file with mode: 0644]
src/cmd/go/internal/generate/generate.go
src/cmd/go/internal/load/pkg.go
src/cmd/go/internal/script/cmds.go
src/cmd/go/internal/script/scripttest/scripttest.go
src/cmd/go/internal/toolchain/select.go
src/cmd/go/internal/vcs/vcs.go
src/cmd/go/internal/work/build.go
src/cmd/go/internal/work/buildid.go
src/cmd/go/internal/work/exec.go
src/cmd/go/internal/work/gccgo.go

diff --git a/src/cmd/go/internal/cfg/bench_test.go b/src/cmd/go/internal/cfg/bench_test.go
new file mode 100644 (file)
index 0000000..2dd9931
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cfg
+
+import (
+       "internal/testenv"
+       "testing"
+)
+
+func BenchmarkLookPath(b *testing.B) {
+       testenv.MustHaveExecPath(b, "go")
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               _, err := LookPath("go")
+               if err != nil {
+                       b.Fatal(err)
+               }
+       }
+}
index 8caa22a93df91f42306a9f782e8659e5b01890f6..a8daa2dfc369ea45a6a47a05ad4157bb2f7ee9bb 100644 (file)
@@ -15,7 +15,6 @@ import (
        "internal/cfg"
        "io"
        "os"
-       "os/exec"
        "path/filepath"
        "runtime"
        "strings"
@@ -161,7 +160,7 @@ func defaultContext() build.Context {
                if ctxt.CgoEnabled {
                        if os.Getenv("CC") == "" {
                                cc := DefaultCC(ctxt.GOOS, ctxt.GOARCH)
-                               if _, err := exec.LookPath(cc); err != nil {
+                               if _, err := LookPath(cc); err != nil {
                                        ctxt.CgoEnabled = false
                                }
                        }
diff --git a/src/cmd/go/internal/cfg/lookpath.go b/src/cmd/go/internal/cfg/lookpath.go
new file mode 100644 (file)
index 0000000..1b0fdc7
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cfg
+
+import (
+       "cmd/go/internal/par"
+       "os/exec"
+)
+
+var lookPathCache par.ErrCache[string, string]
+
+// LookPath wraps exec.LookPath and caches the result
+// which can be called by multiple Goroutines at the same time.
+func LookPath(file string) (path string, err error) {
+       return lookPathCache.Do(file,
+               func() (string, error) {
+                       return exec.LookPath(file)
+               })
+}
index 486de1862d09f94b495d408a64d8ade27175dd86..dbe84d7fd641d51f14a6f3c46cf6d01849349e38 100644 (file)
@@ -487,7 +487,7 @@ func (g *Generator) exec(words []string) {
                // intends to use the same 'go' as 'go generate' itself.
                // Prefer to resolve the binary from GOROOT/bin, and for consistency
                // prefer to resolve any other commands there too.
-               gorootBinPath, err := exec.LookPath(filepath.Join(cfg.GOROOTbin, path))
+               gorootBinPath, err := cfg.LookPath(filepath.Join(cfg.GOROOTbin, path))
                if err == nil {
                        path = gorootBinPath
                }
index 33e46f5f6515d64b1527194c535213b8902ca5f0..3e852603c4719056c582de598e4d216ff5f1870e 100644 (file)
@@ -18,7 +18,6 @@ import (
        "internal/platform"
        "io/fs"
        "os"
-       "os/exec"
        pathpkg "path"
        "path/filepath"
        "runtime"
@@ -2483,7 +2482,7 @@ func (p *Package) setBuildInfo(ctx context.Context, autoVCS bool) {
                        goto omitVCS
                }
                if cfg.BuildBuildvcs == "auto" && vcsCmd != nil && vcsCmd.Cmd != "" {
-                       if _, err := exec.LookPath(vcsCmd.Cmd); err != nil {
+                       if _, err := cfg.LookPath(vcsCmd.Cmd); err != nil {
                                // We fould a repository, but the required VCS tool is not present.
                                // "-buildvcs=auto" means that we should silently drop the VCS metadata.
                                goto omitVCS
index 36e16c55ccdadaca9564a15abe7b2065fa2dba3f..ecd35ff8b122c19abda0a7e147a585237261d5f1 100644 (file)
@@ -5,6 +5,7 @@
 package script
 
 import (
+       "cmd/go/internal/cfg"
        "cmd/go/internal/robustio"
        "errors"
        "fmt"
@@ -824,7 +825,7 @@ func Program(name string, cancel func(*exec.Cmd) error, waitDelay time.Duration)
                },
                func(s *State, args ...string) (WaitFunc, error) {
                        lookPathOnce.Do(func() {
-                               path, pathErr = exec.LookPath(name)
+                               path, pathErr = cfg.LookPath(name)
                        })
                        if pathErr != nil {
                                return nil, pathErr
index 069662493eb90a2482eab43504ebffa87ad252d2..6d7bd7863b9f42b1bebf1906e794c5119d599e34 100644 (file)
@@ -7,10 +7,10 @@ package scripttest
 
 import (
        "bufio"
+       "cmd/go/internal/cfg"
        "cmd/go/internal/script"
        "errors"
        "io"
-       "os/exec"
        "strings"
        "testing"
 )
@@ -137,7 +137,7 @@ func CachedExec() script.Cond {
        return script.CachedCondition(
                "<suffix> names an executable in the test binary's PATH",
                func(name string) (bool, error) {
-                       _, err := exec.LookPath(name)
+                       _, err := cfg.LookPath(name)
                        return err == nil, nil
                })
 }
index a44f393bc0f0dc657941a7ee8676e028438e846f..c3985dedc646204bb0f116030834b1d974f7c6af 100644 (file)
@@ -13,7 +13,6 @@ import (
        "io/fs"
        "log"
        "os"
-       "os/exec"
        "path/filepath"
        "runtime"
        "strconv"
@@ -283,7 +282,7 @@ func Exec(gotoolchain string) {
        // Look in PATH for the toolchain before we download one.
        // This allows custom toolchains as well as reuse of toolchains
        // already installed using go install golang.org/dl/go1.2.3@latest.
-       if exe, err := exec.LookPath(gotoolchain); err == nil {
+       if exe, err := cfg.LookPath(gotoolchain); err == nil {
                execGoToolchain(gotoolchain, "", exe)
        }
 
index 26a8f4b370b612fb96f1c34c2a4f1e2a4813a167..2a881794043715784f70faf720eed71a03e117ee 100644 (file)
@@ -680,7 +680,7 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([
                args = args[2:]
        }
 
-       _, err := exec.LookPath(v.Cmd)
+       _, err := cfg.LookPath(v.Cmd)
        if err != nil {
                fmt.Fprintf(os.Stderr,
                        "go: missing %s command. See https://golang.org/s/gogetcmd\n",
index 8cb53b95d98a423735abae416541f20cc5337c5b..3d82903d2c5f56788da1ac0b283cd208e5634402 100644 (file)
@@ -11,7 +11,6 @@ import (
        "fmt"
        "go/build"
        "os"
-       "os/exec"
        "path/filepath"
        "runtime"
        "strconv"
@@ -899,7 +898,7 @@ func FindExecCmd() []string {
        if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH {
                return ExecCmd
        }
-       path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", cfg.Goos, cfg.Goarch))
+       path, err := cfg.LookPath(fmt.Sprintf("go_%s_%s_exec", cfg.Goos, cfg.Goarch))
        if err == nil {
                ExecCmd = []string{path}
        }
index a1d7599cdd9238336e63d3cb6b6d446c1103cdd0..953d4679cd0125dec5962c4bba1bcfee17d0652e 100644 (file)
@@ -270,7 +270,7 @@ func (b *Builder) gccToolID(name, language string) (id, exe string, err error) {
                }
                exe = fields[0]
                if !strings.ContainsAny(exe, `/\`) {
-                       if lp, err := exec.LookPath(exe); err == nil {
+                       if lp, err := cfg.LookPath(exe); err == nil {
                                exe = lp
                        }
                }
index 0312a58fc581b70261fee6051a228b7e57627780..5ef962f3339571d6e9c7c3e54cf8ddda7eaa4c3b 100644 (file)
@@ -2373,7 +2373,11 @@ func (b *Builder) runOut(a *Action, dir string, env []string, cmdargs ...any) ([
        }
 
        var buf bytes.Buffer
-       cmd := exec.Command(cmdline[0], cmdline[1:]...)
+       path, err := cfg.LookPath(cmdline[0])
+       if err != nil {
+               return nil, err
+       }
+       cmd := exec.Command(path, cmdline[1:]...)
        if cmd.Path != "" {
                cmd.Args[0] = cmd.Path
        }
@@ -2397,7 +2401,7 @@ func (b *Builder) runOut(a *Action, dir string, env []string, cmdargs ...any) ([
 
        cmd.Env = append(cmd.Env, env...)
        start := time.Now()
-       err := cmd.Run()
+       err = cmd.Run()
        if a != nil && a.json != nil {
                aj := a.json
                aj.Cmd = append(aj.Cmd, joinUnambiguously(cmdline))
@@ -3017,7 +3021,7 @@ func (b *Builder) gccCompilerID(compiler string) (id cache.ActionID, ok bool) {
        //
        // Otherwise, we compute a new validation description
        // and compiler id (below).
-       exe, err := exec.LookPath(compiler)
+       exe, err := cfg.LookPath(compiler)
        if err != nil {
                return cache.ActionID{}, false
        }
index edf136df9297a166963fff6403d5df2ec9dff4ef..8ca85be88da2d11aa77bbacff985708da7164696 100644 (file)
@@ -32,7 +32,7 @@ func init() {
        if GccgoName == "" {
                GccgoName = "gccgo"
        }
-       GccgoBin, gccgoErr = exec.LookPath(GccgoName)
+       GccgoBin, gccgoErr = cfg.LookPath(GccgoName)
 }
 
 func (gccgoToolchain) compiler() string {