From 3c8152e28aa16f4d31edd456e089eaf33a1f81a0 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Fri, 4 Nov 2022 15:23:06 -0400 Subject: [PATCH] internal/gcimporter: optimize dependency lookup The old code based on packages.Visit traversed in a deterministic order, and didn't stop when it found its target (the 'return false' only prunes that subtree). This CL replaces it with a precomputation of the PkgPath-to-*Package mapping. The performance difference is small for this test but it nearly dominates on a larger input (e.g. k8s). Example code shouldn't steer users into asymptotic traps. Change-Id: I19f4fc2c25da3d2ae00090704df30a54d8516bf5 Reviewed-on: https://go-review.googlesource.com/c/tools/+/447958 gopls-CI: kokoro TryBot-Result: Gopher Robot Run-TryBot: Alan Donovan Reviewed-by: Robert Findley --- internal/gcimporter/shallow_test.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/internal/gcimporter/shallow_test.go b/internal/gcimporter/shallow_test.go index 084604c7e0..717cb87895 100644 --- a/internal/gcimporter/shallow_test.go +++ b/internal/gcimporter/shallow_test.go @@ -89,6 +89,23 @@ func typecheck(t *testing.T, ppkg *packages.Package) { } // Inv: all files were successfully parsed. + // Build map of dependencies by package path. + // (We don't compute this mapping for the entire + // packages graph because it is not globally consistent.) + depsByPkgPath := make(map[string]*packages.Package) + { + var visit func(*packages.Package) + visit = func(pkg *packages.Package) { + if depsByPkgPath[pkg.PkgPath] == nil { + depsByPkgPath[pkg.PkgPath] = pkg + for path := range pkg.Imports { + visit(pkg.Imports[path]) + } + } + } + visit(ppkg) + } + // importer state var ( insert func(p *types.Package, name string) @@ -100,16 +117,8 @@ func typecheck(t *testing.T, ppkg *packages.Package) { return gcimporter.IImportShallow(fset, importMap, data, imp.PkgPath, insert) } insert = func(p *types.Package, name string) { - // Hunt for p among the transitive dependencies (inefficient). - var imp *packages.Package - packages.Visit([]*packages.Package{ppkg}, func(q *packages.Package) bool { - if q.PkgPath == p.Path() { - imp = q - return false - } - return true - }, nil) - if imp == nil { + imp, ok := depsByPkgPath[p.Path()] + if !ok { t.Fatalf("can't find dependency: %q", p.Path()) } imported, err := loadFromExportData(imp)