Skip to content

Commit d0d0d9e

Browse files
committed
gopls/internal/cache: memoize dependent hash on analysisNode
Benchmarking demonstrated a nontrivial amount of time spent hashing dependency information in the computation of analysisNode.cacheKey. Memoize this hash to reduce cost. Change-Id: Ic123202fbdf00c9de7b3f697c40f593ef798cd42 Reviewed-on: https://go-review.googlesource.com/c/tools/+/617395 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Alan Donovan <[email protected]>
1 parent a19eef6 commit d0d0d9e

File tree

1 file changed

+39
-21
lines changed

1 file changed

+39
-21
lines changed

gopls/internal/cache/analysis.go

+39-21
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,9 @@ type analysisNode struct {
539539
typesOnce sync.Once // guards lazy population of types and typesErr fields
540540
types *types.Package // type information lazily imported from summary
541541
typesErr error // an error producing type information
542+
543+
depHashOnce sync.Once
544+
_depHash file.Hash // memoized hash of data affecting dependents
542545
}
543546

544547
func (an *analysisNode) String() string { return string(an.mp.ID) }
@@ -597,6 +600,40 @@ func (an *analysisNode) _import() (*types.Package, error) {
597600
return an.types, an.typesErr
598601
}
599602

603+
// depHash computes the hash of node information that may affect other nodes
604+
// depending on this node: the package path, export hash, and action results.
605+
//
606+
// The result is memoized to avoid redundant work when analysing multiple
607+
// dependents.
608+
func (an *analysisNode) depHash() file.Hash {
609+
an.depHashOnce.Do(func() {
610+
hasher := sha256.New()
611+
fmt.Fprintf(hasher, "dep: %s\n", an.mp.PkgPath)
612+
fmt.Fprintf(hasher, "export: %s\n", an.summary.DeepExportHash)
613+
614+
// action results: errors and facts
615+
actions := an.summary.Actions
616+
names := make([]string, 0, len(actions))
617+
for name := range actions {
618+
names = append(names, name)
619+
}
620+
sort.Strings(names)
621+
for _, name := range names {
622+
summary := actions[name]
623+
fmt.Fprintf(hasher, "action %s\n", name)
624+
if summary.Err != "" {
625+
fmt.Fprintf(hasher, "error %s\n", summary.Err)
626+
} else {
627+
fmt.Fprintf(hasher, "facts %s\n", summary.FactsHash)
628+
// We can safely omit summary.diagnostics
629+
// from the key since they have no downstream effect.
630+
}
631+
}
632+
hasher.Sum(an._depHash[:0])
633+
})
634+
return an._depHash
635+
}
636+
600637
// analyzeSummary is a gob-serializable summary of successfully
601638
// applying a list of analyzers to a package.
602639
type analyzeSummary struct {
@@ -770,27 +807,8 @@ func (an *analysisNode) cacheKey() [sha256.Size]byte {
770807

771808
// vdeps, in PackageID order
772809
for _, vdep := range moremaps.Sorted(an.succs) {
773-
fmt.Fprintf(hasher, "dep: %s\n", vdep.mp.PkgPath)
774-
fmt.Fprintf(hasher, "export: %s\n", vdep.summary.DeepExportHash)
775-
776-
// action results: errors and facts
777-
actions := vdep.summary.Actions
778-
names := make([]string, 0, len(actions))
779-
for name := range actions {
780-
names = append(names, name)
781-
}
782-
sort.Strings(names)
783-
for _, name := range names {
784-
summary := actions[name]
785-
fmt.Fprintf(hasher, "action %s\n", name)
786-
if summary.Err != "" {
787-
fmt.Fprintf(hasher, "error %s\n", summary.Err)
788-
} else {
789-
fmt.Fprintf(hasher, "facts %s\n", summary.FactsHash)
790-
// We can safely omit summary.diagnostics
791-
// from the key since they have no downstream effect.
792-
}
793-
}
810+
hash := vdep.depHash()
811+
hasher.Write(hash[:])
794812
}
795813

796814
var hash [sha256.Size]byte

0 commit comments

Comments
 (0)