blob: b8ed2057ad5d03903621ce7b0c4a1dc1a5923d66 [file] [log] [blame]
// digest_counter returns counts of digests for various views on a Tile.
package digest_counter
import (
"go.skia.org/infra/go/paramtools"
"go.skia.org/infra/golden/go/shared"
"go.skia.org/infra/golden/go/tiling"
"go.skia.org/infra/golden/go/types"
)
// DigestCount maps a digest to a count. These counts are the number
// of times a digest was seen in a given scenario.
type DigestCount map[types.Digest]int
// DigestCounter allows querying for digest counts for a digest in different ways.
// For example, how many times did this tile see a given digest in a given
// test or a given trace? The results can be further filtered using
// ByQuery.
// It should be immutable once created and therefore thread-safe.
type DigestCounter interface {
// ByTest returns a map of test_name -> DigestCount
ByTest() map[types.TestName]DigestCount
// ByTrace returns a map of trace_id -> DigestCount
ByTrace() map[tiling.TraceID]DigestCount
// MaxDigestsByTest returns a map of all tests seen
// in the tile mapped to the digest that showed up
// the most in that test.
MaxDigestsByTest() map[types.TestName]types.DigestSet
// ByQuery returns a DigestCount of all the digests that match the given query in
// the provided tile. Note that this will recompute the digests across the entire tile.
ByQuery(tile *tiling.Tile, query paramtools.ParamSet) DigestCount
}
// Counter implements DigestCounter
type Counter struct {
traceDigestCount map[tiling.TraceID]DigestCount
testDigestCount map[types.TestName]DigestCount
maxCountsByTest map[types.TestName]types.DigestSet
}
// New creates a new Counter object.
func New(tile *tiling.Tile) *Counter {
trace, test, maxCountsByTest := calculate(tile)
return &Counter{
traceDigestCount: trace,
testDigestCount: test,
maxCountsByTest: maxCountsByTest,
}
}
// ByTest implements the DigestCounter interface.
func (t *Counter) ByTest() map[types.TestName]DigestCount {
return t.testDigestCount
}
// ByTrace implements the DigestCounter interface.
func (t *Counter) ByTrace() map[tiling.TraceID]DigestCount {
return t.traceDigestCount
}
// MaxDigestsByTest implements the DigestCounter interface.
func (t *Counter) MaxDigestsByTest() map[types.TestName]types.DigestSet {
return t.maxCountsByTest
}
// ByQuery returns a DigestCount of all the digests that match the given query in
// the provided tile.
func (t *Counter) ByQuery(tile *tiling.Tile, query paramtools.ParamSet) DigestCount {
return countByQuery(tile, t.traceDigestCount, query)
}
// countByQuery does the actual work of ByQuery.
func countByQuery(tile *tiling.Tile, traceDigestCount map[tiling.TraceID]DigestCount, query paramtools.ParamSet) DigestCount {
ret := DigestCount{}
for k, tr := range tile.Traces {
if tr.Matches(query) {
if _, ok := traceDigestCount[k]; !ok {
continue
}
for digest, n := range traceDigestCount[k] {
ret[digest] += n
}
}
}
return ret
}
// calculate computes the counts by trace id and test name from the given Tile.
func calculate(tile *tiling.Tile) (map[tiling.TraceID]DigestCount, map[types.TestName]DigestCount, map[types.TestName]types.DigestSet) {
defer shared.NewMetricsTimer("digest_counter_calculate").Stop()
traceDigestCount := map[tiling.TraceID]DigestCount{}
testDigestCount := map[types.TestName]DigestCount{}
for k, trace := range tile.Traces {
dCount := DigestCount{}
for _, d := range trace.Digests {
if d == tiling.MissingDigest {
continue
}
if n, ok := dCount[d]; ok {
dCount[d] = n + 1
} else {
dCount[d] = 1
}
}
traceDigestCount[k] = dCount
testName := trace.TestName()
if t, ok := testDigestCount[testName]; ok {
for digest, n := range dCount {
t[digest] += n
}
} else {
cp := DigestCount{}
for k, v := range dCount {
cp[k] = v
}
testDigestCount[testName] = cp
}
}
maxCountsByTest := make(map[types.TestName]types.DigestSet, len(testDigestCount))
for testName, dCount := range testDigestCount {
maxCount := 0
for _, count := range dCount {
if count > maxCount {
maxCount = count
}
}
maxCountsByTest[testName] = types.DigestSet{}
for digest, count := range dCount {
if count == maxCount {
maxCountsByTest[testName][digest] = true
}
}
}
return traceDigestCount, testDigestCount, maxCountsByTest
}
// Make sure Counter fulfills the DigestCounter Interface
var _ DigestCounter = (*Counter)(nil)