Skip to content

Commit

Permalink
cmd/go: parallelize matchPackages work in each module
Browse files Browse the repository at this point in the history
In each module matchPackages looks in, when doing the walk, do the
scanDir call in a par.Queue so all the read work can be done in
parallel.

Change-Id: I27153dbb3a2ed417ca24972f47134e9e914a55d1
Reviewed-on: https://go-review.googlesource.com/c/go/+/404097
Reviewed-by: Michael Matloob <matloob@golang.org>
Run-TryBot: Michael Matloob <matloob@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
  • Loading branch information
matloob committed Jun 16, 2022
1 parent 1d9d99b commit 74f1fa6
Showing 1 changed file with 26 additions and 12 deletions.
38 changes: 26 additions & 12 deletions src/cmd/go/internal/modload/search.go
Expand Up @@ -12,12 +12,16 @@ import (
"os"
"path"
"path/filepath"
"runtime"
"sort"
"strings"
"sync"

"cmd/go/internal/cfg"
"cmd/go/internal/fsys"
"cmd/go/internal/imports"
"cmd/go/internal/modindex"
"cmd/go/internal/par"
"cmd/go/internal/search"

"golang.org/x/mod/module"
Expand All @@ -43,9 +47,15 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
treeCanMatch = search.TreeCanMatchPattern(m.Pattern())
}

var mu sync.Mutex
have := map[string]bool{
"builtin": true, // ignore pseudo-package that exists only for documentation
}
addPkg := func(p string) {
mu.Lock()
m.Pkgs = append(m.Pkgs, p)
mu.Unlock()
}
if !cfg.BuildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
Expand All @@ -56,6 +66,8 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
pruneGoMod
)

q := par.NewQueue(runtime.GOMAXPROCS(0))

walkPkgs := func(root, importPathRoot string, prune pruning) {
root = filepath.Clean(root)
err := fsys.Walk(root, func(path string, fi fs.FileInfo, err error) error {
Expand Down Expand Up @@ -110,9 +122,11 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
if !have[name] {
have[name] = true
if isMatch(name) {
if _, _, err := scanDir(root, path, tags); err != imports.ErrNoGo {
m.Pkgs = append(m.Pkgs, name)
}
q.Add(func() {
if _, _, err := scanDir(root, path, tags); err != imports.ErrNoGo {
addPkg(name)
}
})
}
}

Expand All @@ -126,6 +140,12 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
}
}

// Wait for all in-flight operations to complete before returning.
defer func() {
<-q.Idle()
sort.Strings(m.Pkgs) // sort everything we added for determinism
}()

if filter == includeStd {
walkPkgs(cfg.GOROOTsrc, "", pruneGoMod)
if treeCanMatch("cmd") {
Expand Down Expand Up @@ -169,7 +189,7 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
modPrefix = mod.Path
}
if mi, err := modindex.Get(root); err == nil {
walkFromIndex(ctx, m, tags, root, mi, have, modPrefix)
walkFromIndex(mi, modPrefix, isMatch, treeCanMatch, tags, have, addPkg)
continue
} else if !errors.Is(err, modindex.ErrNotIndexed) {
m.AddError(err)
Expand All @@ -188,13 +208,7 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
// walkFromIndex matches packages in a module using the module index. modroot
// is the module's root directory on disk, index is the ModuleIndex for the
// module, and importPathRoot is the module's path prefix.
func walkFromIndex(ctx context.Context, m *search.Match, tags map[string]bool, modroot string, index *modindex.ModuleIndex, have map[string]bool, importPathRoot string) {
isMatch := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
if !m.IsMeta() {
isMatch = search.MatchPattern(m.Pattern())
treeCanMatch = search.TreeCanMatchPattern(m.Pattern())
}
func walkFromIndex(index *modindex.ModuleIndex, importPathRoot string, isMatch, treeCanMatch func(string) bool, tags, have map[string]bool, addPkg func(string)) {
loopPackages:
for _, reldir := range index.Packages() {
// Avoid .foo, _foo, and testdata subdirectory trees.
Expand Down Expand Up @@ -232,7 +246,7 @@ loopPackages:
have[name] = true
if isMatch(name) {
if _, _, err := index.ScanDir(reldir, tags); err != imports.ErrNoGo {
m.Pkgs = append(m.Pkgs, name)
addPkg(name)
}
}
}
Expand Down

0 comments on commit 74f1fa6

Please sign in to comment.