Index: fuzzer/go/frontend/syncer/fuzz_syncer.go |
diff --git a/fuzzer/go/frontend/syncer/fuzz_syncer.go b/fuzzer/go/frontend/syncer/fuzz_syncer.go |
index b620a72e6699e108655f1b44ae3c119901558690..01b2d1881901ca45b19347e3c7ed1f4c4cea5811 100644 |
--- a/fuzzer/go/frontend/syncer/fuzz_syncer.go |
+++ b/fuzzer/go/frontend/syncer/fuzz_syncer.go |
@@ -12,6 +12,7 @@ import ( |
"go.skia.org/infra/fuzzer/go/config" |
"go.skia.org/infra/fuzzer/go/frontend/gsloader" |
"go.skia.org/infra/go/gs" |
+ "go.skia.org/infra/go/util" |
"google.golang.org/cloud/storage" |
) |
@@ -22,7 +23,8 @@ type FuzzSyncer struct { |
countMutex sync.Mutex |
storageClient *storage.Client |
gsLoader *gsloader.GSLoader |
- lastCount map[string]FuzzCount |
+ lastCount map[string]FuzzCount // maps category->FuzzCount |
+ fuzzNameCache map[string]util.StringSet // maps key->FuzzNames |
} |
// FuzzCount is a struct that holds the counts of fuzzes. |
@@ -30,8 +32,8 @@ type FuzzCount struct { |
TotalBad int `json:"totalBadCount"` |
TotalGrey int `json:"totalGreyCount"` |
// "This" means "newly introduced/fixed in this revision" |
- ThisBad int `json:"thisBadCount"` |
- ThisGrey int `json:"thisGreyCount"` |
+ ThisBad int `json:"thisBadCount"` |
+ ThisRegression int `json:"thisRegressionCount"` |
} |
// NewFuzzSyncer creates a FuzzSyncer and returns it. |
@@ -39,6 +41,7 @@ func New(s *storage.Client) *FuzzSyncer { |
return &FuzzSyncer{ |
storageClient: s, |
lastCount: make(map[string]FuzzCount), |
+ fuzzNameCache: make(map[string]util.StringSet), |
} |
} |
@@ -72,39 +75,27 @@ func (f *FuzzSyncer) Refresh() { |
} |
f.countMutex.Lock() |
defer f.countMutex.Unlock() |
- allCurrentNames := []string{} |
+ allBadFuzzes := util.NewStringSet() |
for _, cat := range common.FUZZ_CATEGORIES { |
lastCount := FuzzCount{} |
- currentBadNames, err := common.GetAllFuzzNamesInFolder(f.storageClient, fmt.Sprintf("%s/%s/bad", cat, currRevision)) |
- if err != nil { |
- glog.Errorf("Problem getting total bad fuzz counts: %s", err) |
- } else { |
- lastCount.TotalBad = len(currentBadNames) |
- allCurrentNames = append(allCurrentNames, currentBadNames...) |
- } |
- if previousBadNames, err := common.GetAllFuzzNamesInFolder(f.storageClient, fmt.Sprintf("%s/%s/bad", cat, prevRevision)); err != nil { |
- glog.Errorf("Problem getting this bad fuzz counts: %s", err) |
- } else { |
- lastCount.ThisBad = lastCount.TotalBad - len(previousBadNames) |
- } |
+ // Previous fuzzes and current grey fuzzes can be drawn from the cache, if they aren't there. |
+ previousGreyNames := f.getOrLookUpFuzzNames("grey", cat, prevRevision) |
+ previousBadNames := f.getOrLookUpFuzzNames("bad", cat, prevRevision) |
+ currentGreyNames := f.getOrLookUpFuzzNames("grey", cat, currRevision) |
+ // always fetch current counts |
+ currentBadNames := f.getFuzzNames("bad", cat, currRevision) |
+ lastCount.TotalBad = len(currentBadNames) |
+ lastCount.TotalGrey = len(currentGreyNames) |
+ lastCount.ThisBad = len(currentBadNames.Complement(previousBadNames).Complement(previousGreyNames)) |
+ lastCount.ThisRegression = len(previousGreyNames.Intersect(currentBadNames)) |
+ allBadFuzzes = allBadFuzzes.Union(currentBadNames) |
- if currentGreyNames, err := common.GetAllFuzzNamesInFolder(f.storageClient, fmt.Sprintf("%s/%s/grey", cat, currRevision)); err != nil { |
- glog.Errorf("Problem getting total grey fuzz counts: %s", err) |
- } else { |
- lastCount.TotalGrey = len(currentGreyNames) |
- } |
- |
- if previousGreyNames, err := common.GetAllFuzzNamesInFolder(f.storageClient, fmt.Sprintf("%s/%s/grey", cat, prevRevision)); err != nil { |
- glog.Errorf("Problem getting this grey fuzz counts: %s", err) |
- } else { |
- lastCount.ThisGrey = lastCount.TotalGrey - len(previousGreyNames) |
- } |
f.lastCount[cat] = lastCount |
} |
- if err = f.updateLoadedBinaryFuzzes(allCurrentNames); err != nil { |
+ if err = f.updateLoadedBinaryFuzzes(allBadFuzzes.Keys()); err != nil { |
glog.Errorf("Problem updating loaded binary fuzzes: %s", err) |
} |
} |
@@ -128,6 +119,40 @@ func (f *FuzzSyncer) getMostRecentOldRevision() (string, error) { |
return newestHash, nil |
} |
+// getOrLookUpFuzzNames first checks the cache for a StringSet of fuzz names linked to a given |
+// tuple of fuzzType (bad or grey), category, revision. If such a thing is not in the cache, it |
+// fetches it via getFuzzNames() and caches it for next time. |
+func (f *FuzzSyncer) getOrLookUpFuzzNames(fuzzType, category, revision string) util.StringSet { |
+ key := strings.Join([]string{fuzzType, category, revision}, "|") |
+ if s, has := f.fuzzNameCache[key]; has { |
+ return s |
+ } |
+ s := f.getFuzzNames(fuzzType, category, revision) |
+ // cache it |
+ f.fuzzNameCache[key] = s |
+ return s |
+} |
+ |
+// getFuzzNames gets all the fuzz names belonging to a fuzzType, category, revision tuple from |
+// Google Storage. It tries two different ways to do this, first by reading a |
+// (bad|grey)_fuzz_names file, which exists in previous revisions. Second, it manually counts |
+// all fuzzes in the given GCS folder. |
+func (f *FuzzSyncer) getFuzzNames(fuzzType, category, revision string) util.StringSet { |
+ // The file stored, if it exists, is a pipe seperated list. |
+ if names, err := gs.FileContentsFromGS(f.storageClient, config.GS.Bucket, fmt.Sprintf("%s/%s/%s_fuzz_names.txt", category, revision, fuzzType)); err == nil { |
+ return util.NewStringSet(strings.Split(string(names), "|")) |
+ } else { |
+ glog.Infof("Could not find cached names, downloading them the long way, instead: %s", err) |
+ } |
+ |
+ if names, err := common.GetAllFuzzNamesInFolder(f.storageClient, fmt.Sprintf("%s/%s/%s", category, revision, fuzzType)); err != nil { |
+ glog.Errorf("Problem fetching %s %s fuzzes at revision %s: %s", fuzzType, category, revision, err) |
+ return nil |
+ } else { |
+ return util.NewStringSet(names) |
+ } |
+} |
+ |
// updateLoadedBinaryFuzzes uses gsLoader to download the fuzzes that are currently not |
// in the fuzz report tree / cache. |
func (f *FuzzSyncer) updateLoadedBinaryFuzzes(currentBadFuzzHashes []string) error { |