Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(917)

Side by Side Diff: golden/go/analysis/analysis.go

Issue 884943003: Ignore traces (Closed) Base URL: https://skia.googlesource.com/buildbot@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « golden/Makefile ('k') | golden/go/analysis/analysis_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 package analysis 1 package analysis
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 "net/url" 5 "net/url"
6 "sort" 6 "sort"
7 "sync" 7 "sync"
8 "time" 8 "time"
9 9
10 » metrics "github.com/rcrowley/go-metrics" 10 » "github.com/rcrowley/go-metrics"
11 "github.com/skia-dev/glog" 11 "github.com/skia-dev/glog"
12 12
13 "skia.googlesource.com/buildbot.git/go/util" 13 "skia.googlesource.com/buildbot.git/go/util"
14 "skia.googlesource.com/buildbot.git/golden/go/diff" 14 "skia.googlesource.com/buildbot.git/golden/go/diff"
15 "skia.googlesource.com/buildbot.git/golden/go/expstorage" 15 "skia.googlesource.com/buildbot.git/golden/go/expstorage"
16 "skia.googlesource.com/buildbot.git/golden/go/types" 16 "skia.googlesource.com/buildbot.git/golden/go/types"
17 "skia.googlesource.com/buildbot.git/perf/go/human" 17 "skia.googlesource.com/buildbot.git/perf/go/human"
18 ptypes "skia.googlesource.com/buildbot.git/perf/go/types" 18 ptypes "skia.googlesource.com/buildbot.git/perf/go/types"
19 ) 19 )
20 20
21 var (
22 // The number of times we've successfully loaded and processed a tile.
23 runsCounter metrics.Counter
24
25 // The number of times an error has ocurred when trying to load a tile.
26 errorTileLoadingCounter metrics.Counter
27 )
28
29 func init() {
30 runsCounter = metrics.NewRegisteredCounter("analysis.runs", metrics.Defa ultRegistry)
31 errorTileLoadingCounter = metrics.NewRegisteredCounter("analysis.errors" , metrics.DefaultRegistry)
32 }
33
21 type PathToURLConverter func(string) string 34 type PathToURLConverter func(string) string
22 35
23 // LabeledTrace stores a Trace with labels and digests. CommitIds, Digests and 36 // LabeledTrace stores a Trace with labels and digests. CommitIds, Digests and
24 // Labels are of the same length, identical indices refer to the same digest. 37 // Labels are of the same length, identical indices refer to the same digest.
25 type LabeledTrace struct { 38 type LabeledTrace struct {
26 » Params map[string]string 39 » Params map[string]string
27 » CommitIds []int 40 » CommitIds []int
28 » Digests []string 41 » Digests []string
29 » Labels []types.Label 42 » Labels []types.Label
30 » Id int 43 » Id int
44 » IgnoreRules []*types.IgnoreRule
31 } 45 }
32 46
33 func NewLabeledTrace(params map[string]string, capacity int, traceId int) *Label edTrace { 47 func NewLabeledTrace(params map[string]string, capacity int, traceId int) *Label edTrace {
34 return &LabeledTrace{ 48 return &LabeledTrace{
35 » » Params: params, 49 » » Params: params,
36 » » CommitIds: make([]int, 0, capacity), 50 » » CommitIds: make([]int, 0, capacity),
37 » » Digests: make([]string, 0, capacity), 51 » » Digests: make([]string, 0, capacity),
38 » » Labels: make([]types.Label, 0, capacity), 52 » » Labels: make([]types.Label, 0, capacity),
39 » » Id: traceId, 53 » » Id: traceId,
54 » » IgnoreRules: []*types.IgnoreRule{},
40 } 55 }
41 } 56 }
42 57
43 // addLabledDigests adds the given tripples of commitIds, digests and labels to this LabeledTrace. 58 // addLabledDigests adds the given tripples of commitIds, digests and labels to this LabeledTrace.
44 func (lt *LabeledTrace) addLabeledDigests(commitIds []int, digests []string, lab els []types.Label) { 59 func (lt *LabeledTrace) addLabeledDigests(commitIds []int, digests []string, lab els []types.Label) {
45 lt.CommitIds = append(lt.CommitIds, commitIds...) 60 lt.CommitIds = append(lt.CommitIds, commitIds...)
46 lt.Digests = append(lt.Digests, digests...) 61 lt.Digests = append(lt.Digests, digests...)
47 lt.Labels = append(lt.Labels, labels...) 62 lt.Labels = append(lt.Labels, labels...)
48 } 63 }
49 64
65 // addIgnoreRules attaches the ignore rules that match his trace.
66 func (lt *LabeledTrace) addIgnoreRules(newRules []*types.IgnoreRule) {
67 lt.IgnoreRules = append(lt.IgnoreRules, newRules...)
68 }
69
50 // LabeledTile aggregates the traces of a tile and provides a slice of commits 70 // LabeledTile aggregates the traces of a tile and provides a slice of commits
51 // that the commitIds in LabeledTrace refer to. 71 // that the commitIds in LabeledTrace refer to.
52 // LabeledTile and LabeledTrace store the cannonical information 72 // LabeledTile and LabeledTrace store the cannonical information
53 // extracted from the unterlying tile store. The (redundant) output data is 73 // extracted from the unterlying tile store. The (redundant) output data is
54 // derived from these. 74 // derived from these.
55 type LabeledTile struct { 75 type LabeledTile struct {
56 Commits []*ptypes.Commit 76 Commits []*ptypes.Commit
57 77
58 // Traces are indexed by the primary key (test name). This is somewhat 78 // Traces are indexed by the primary key (test name). This is somewhat
59 // redundant, but this also output format. 79 // redundant, but this also output format.
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 // GUITileCounts is an output type for the aggregated label counts. 140 // GUITileCounts is an output type for the aggregated label counts.
121 type GUITileCounts struct { 141 type GUITileCounts struct {
122 Commits []*ptypes.Commit `json:"commits"` 142 Commits []*ptypes.Commit `json:"commits"`
123 Ticks []interface{} `json:"ticks"` 143 Ticks []interface{} `json:"ticks"`
124 Aggregated *LabelCounts `json:"aggregated"` 144 Aggregated *LabelCounts `json:"aggregated"`
125 Counts map[string]*LabelCounts `json:"counts"` 145 Counts map[string]*LabelCounts `json:"counts"`
126 AllParams map[string][]string `json:"allParams"` 146 AllParams map[string][]string `json:"allParams"`
127 Query map[string][]string `json:"query"` 147 Query map[string][]string `json:"query"`
128 } 148 }
129 149
150 // AnalyzeState captures the state of a partition of the incoming data.
151 // When a tile is read from disk it is partitioned into two tiles: current
152 // and ignored. current contains everything we want to be able to review
153 // continuously and ignored contains all ignored traces.
154 // This struct is the container for one of these partitions and the derived
155 // information.
156 type AnalyzeState struct {
157 // Canonical data structure to hold our information about commits, diges ts
158 // and labels.
159 Tile *LabeledTile
160
161 // Index to query the Tile.
162 Index *LabeledTileIndex
163
164 // Output data structures that are derived from Tile.
165 TileCounts *GUITileCounts
166 TestDetails *GUITestDetails
167 Status *GUIStatus
168 }
169
130 // Analyzer continuously manages tasks like polling for new traces 170 // Analyzer continuously manages tasks like polling for new traces
131 // on disk and generating diffs between images. It is the primary interface 171 // on disk and generating diffs between images. It is the primary interface
132 // to be called by the HTTP frontend. 172 // to be called by the HTTP frontend.
133 type Analyzer struct { 173 type Analyzer struct {
134 » expStore expstorage.ExpectationsStore 174 » expStore expstorage.ExpectationsStore
135 » diffStore diff.DiffStore 175 » diffStore diff.DiffStore
136 » tileStore ptypes.TileStore 176 » tileStore ptypes.TileStore
177 » ignoreStore types.IgnoreStore
137 178
138 » // Canonical data structure to hold our information about commits, diges ts 179 » current *AnalyzeState
139 » // and labels. 180 » ignored *AnalyzeState
140 » currentTile *LabeledTile
141
142 » // Index to query the current tile.
143 » currentIndex *LabeledTileIndex
144
145 » // Output data structures that are derived from currentTile.
146 » currentTileCounts *GUITileCounts
147 » currentTestDetails *GUITestDetails
148 » currentStatus *GUIStatus
149
150 » // Maps from trace ids to the actual instances of LabeledTrace.
151 » traceMap map[int]*LabeledTrace
152 181
153 // converter supplied by the client of the type to convert a path to a U RL 182 // converter supplied by the client of the type to convert a path to a U RL
154 pathToURLConverter PathToURLConverter 183 pathToURLConverter PathToURLConverter
155 184
156 // Lock to protect the expectations and current* variables. 185 // Lock to protect the expectations and current* variables.
157 mutex sync.RWMutex 186 mutex sync.RWMutex
158 187
159 // Counts the number of times the main event loop has executed. 188 // Counts the number of times the main event loop has executed.
160 // This is for testing only. 189 // This is for testing only.
161 loopCounter int 190 loopCounter int
162 } 191 }
163 192
164 func NewAnalyzer(expStore expstorage.ExpectationsStore, tileStore ptypes.TileSto re, diffStore diff.DiffStore, puConverter PathToURLConverter, timeBetweenPolls t ime.Duration) *Analyzer { 193 func NewAnalyzer(expStore expstorage.ExpectationsStore, tileStore ptypes.TileSto re, diffStore diff.DiffStore, ignoreStore types.IgnoreStore, puConverter PathToU RLConverter, timeBetweenPolls time.Duration) *Analyzer {
165 result := &Analyzer{ 194 result := &Analyzer{
166 expStore: expStore, 195 expStore: expStore,
167 diffStore: diffStore, 196 diffStore: diffStore,
168 tileStore: tileStore, 197 tileStore: tileStore,
198 ignoreStore: ignoreStore,
169 pathToURLConverter: puConverter, 199 pathToURLConverter: puConverter,
170 200
171 » » currentTile: NewLabeledTile(), 201 » » current: &AnalyzeState{},
202 » » ignored: &AnalyzeState{},
172 } 203 }
173 204
174 go result.loop(timeBetweenPolls) 205 go result.loop(timeBetweenPolls)
175 return result 206 return result
176 } 207 }
177 208
178 // GetTileCounts returns an entire Tile which is a collection of 'traces' over 209 // GetTileCounts returns an entire Tile which is a collection of 'traces' over
179 // a series of commits. Each trace contains the digests and their labels 210 // a series of commits. Each trace contains the digests and their labels
180 // based on our knowledge about digests (expectations). 211 // based on our knowledge about digests (expectations).
181 func (a *Analyzer) GetTileCounts(query map[string][]string) (*GUITileCounts, err or) { 212 func (a *Analyzer) GetTileCounts(query map[string][]string) (*GUITileCounts, err or) {
182 a.mutex.RLock() 213 a.mutex.RLock()
183 defer a.mutex.RUnlock() 214 defer a.mutex.RUnlock()
184 215
185 if len(query) > 0 { 216 if len(query) > 0 {
186 tile, effectiveQuery := a.getSubTile(query) 217 tile, effectiveQuery := a.getSubTile(query)
187 if len(effectiveQuery) > 0 { 218 if len(effectiveQuery) > 0 {
188 » » » ret := a.getOutputCounts(tile) 219 » » » ret := a.getOutputCounts(tile, a.current.Index)
189 ret.Query = effectiveQuery 220 ret.Query = effectiveQuery
190 return ret, nil 221 return ret, nil
191 } 222 }
192 } 223 }
193 224
194 » return a.currentTileCounts, nil 225 » return a.current.TileCounts, nil
195 } 226 }
196 227
197 // ListTestDetails returns a list of triage details based on the supplied 228 // ListTestDetails returns a list of triage details based on the supplied
198 // query. It's complementary to GetTestDetails which returns a single test 229 // query. It's complementary to GetTestDetails which returns a single test
199 // detail. 230 // detail.
200 // TODO(stephana): This should provide pagination since the list is potentially 231 // TODO(stephana): This should provide pagination since the list is potentially
201 // very long. If we don't add pagination, this should be merged with 232 // very long. If we don't add pagination, this should be merged with
202 // GetTestDetail. 233 // GetTestDetail.
203 func (a *Analyzer) ListTestDetails(query map[string][]string) (*GUITestDetails, error) { 234 func (a *Analyzer) ListTestDetails(query map[string][]string) (*GUITestDetails, error) {
204 a.mutex.RLock() 235 a.mutex.RLock()
205 defer a.mutex.RUnlock() 236 defer a.mutex.RUnlock()
206 237
207 if len(query) == 0 { 238 if len(query) == 0 {
208 » » return a.currentTestDetails, nil 239 » » return a.current.TestDetails, nil
209 } 240 }
210 241
211 effectiveQuery := make(map[string][]string, len(query)) 242 effectiveQuery := make(map[string][]string, len(query))
212 foundUntriaged := a.getUntriagedTestDetails(query, effectiveQuery, true) 243 foundUntriaged := a.getUntriagedTestDetails(query, effectiveQuery, true)
213 tests := make([]*GUITestDetail, 0, len(foundUntriaged)) 244 tests := make([]*GUITestDetail, 0, len(foundUntriaged))
214 245
215 for testName, untriaged := range foundUntriaged { 246 for testName, untriaged := range foundUntriaged {
216 » » testDetail := a.currentTestDetails.lookup(testName) 247 » » testDetail := a.current.TestDetails.lookup(testName)
217 tests = append(tests, &GUITestDetail{ 248 tests = append(tests, &GUITestDetail{
218 Name: testName, 249 Name: testName,
219 Untriaged: untriaged, 250 Untriaged: untriaged,
220 Positive: testDetail.Positive, 251 Positive: testDetail.Positive,
221 Negative: testDetail.Negative, 252 Negative: testDetail.Negative,
222 }) 253 })
223 } 254 }
224 255
225 // Sort the test details. 256 // Sort the test details.
226 sort.Sort(GUITestDetailSortable(tests)) 257 sort.Sort(GUITestDetailSortable(tests))
227 258
228 return &GUITestDetails{ 259 return &GUITestDetails{
229 » » Commits: a.currentTestDetails.Commits, 260 » » Commits: a.current.TestDetails.Commits,
230 » » AllParams: a.currentIndex.getAllParams(query), 261 » » AllParams: a.current.Index.getAllParams(query),
231 Query: effectiveQuery, 262 Query: effectiveQuery,
232 Tests: tests, 263 Tests: tests,
233 }, nil 264 }, nil
234 } 265 }
235 266
236 // PolyGUISimple is basic info about a test. Returned from PolyListTestSimple. 267 // PolyGUISimple is basic info about a test. Returned from PolyListTestSimple.
237 type PolyGUISimple struct { 268 type PolyGUISimple struct {
238 Name string `json:"name"` 269 Name string `json:"name"`
239 Diameter int `json:"diameter"` 270 Diameter int `json:"diameter"`
240 Pos int `json:"pos"` 271 Pos int `json:"pos"`
(...skipping 27 matching lines...) Expand all
268 if hasQuery { 299 if hasQuery {
269 for _, tr := range tile.Traces { 300 for _, tr := range tile.Traces {
270 if ptypes.Matches(tr, query) { 301 if ptypes.Matches(tr, query) {
271 if name, ok := tr.Params()[types.PRIMARY_KEY_FIE LD]; ok { 302 if name, ok := tr.Params()[types.PRIMARY_KEY_FIE LD]; ok {
272 names[name] = true 303 names[name] = true
273 } 304 }
274 } 305 }
275 } 306 }
276 } 307 }
277 308
278 » for _, t := range a.currentTestDetails.Tests { 309 » for _, t := range a.current.TestDetails.Tests {
279 if hasQuery { 310 if hasQuery {
280 if _, ok := names[t.Name]; !ok { 311 if _, ok := names[t.Name]; !ok {
281 continue 312 continue
282 } 313 }
283 } 314 }
284 315
285 ret = append(ret, &PolyGUISimple{ 316 ret = append(ret, &PolyGUISimple{
286 Name: t.Name, 317 Name: t.Name,
287 Diameter: t.Diameter, 318 Diameter: t.Diameter,
288 Pos: len(t.Positive), 319 Pos: len(t.Positive),
(...skipping 21 matching lines...) Expand all
310 // If query is not empty then we will return traces that match the query. 341 // If query is not empty then we will return traces that match the query.
311 // If the query is empty and testName is not empty we will return the 342 // If the query is empty and testName is not empty we will return the
312 // traces of the corresponding test.If both query and testName are empty 343 // traces of the corresponding test.If both query and testName are empty
313 // we will return all traces. 344 // we will return all traces.
314 // TODO (stephana): If the result is too big we should add pagination. 345 // TODO (stephana): If the result is too big we should add pagination.
315 func (a *Analyzer) GetTestDetails(testName string, query map[string][]string) (* GUITestDetails, error) { 346 func (a *Analyzer) GetTestDetails(testName string, query map[string][]string) (* GUITestDetails, error) {
316 a.mutex.RLock() 347 a.mutex.RLock()
317 defer a.mutex.RUnlock() 348 defer a.mutex.RUnlock()
318 349
319 var effectiveQuery map[string][]string 350 var effectiveQuery map[string][]string
320 » testDetail := a.currentTestDetails.lookup(testName) 351 » testDetail := a.current.TestDetails.lookup(testName)
321 untriaged := testDetail.Untriaged 352 untriaged := testDetail.Untriaged
322 if len(query) > 0 { 353 if len(query) > 0 {
323 effectiveQuery = map[string][]string{} 354 effectiveQuery = map[string][]string{}
324 355
325 // Filter by only this test. 356 // Filter by only this test.
326 query[types.PRIMARY_KEY_FIELD] = []string{testName} 357 query[types.PRIMARY_KEY_FIELD] = []string{testName}
327 foundUntriaged := a.getUntriagedTestDetails(query, effectiveQuer y, false) 358 foundUntriaged := a.getUntriagedTestDetails(query, effectiveQuer y, false)
328 delete(effectiveQuery, types.PRIMARY_KEY_FIELD) 359 delete(effectiveQuery, types.PRIMARY_KEY_FIELD)
329 360
330 // Only consider the result if some query parameters were valid. 361 // Only consider the result if some query parameters were valid.
331 if len(effectiveQuery) > 0 { 362 if len(effectiveQuery) > 0 {
332 if temp, ok := foundUntriaged[testName]; ok { 363 if temp, ok := foundUntriaged[testName]; ok {
333 untriaged = temp 364 untriaged = temp
334 } else { 365 } else {
335 untriaged = map[string]*GUIUntriagedDigest{} 366 untriaged = map[string]*GUIUntriagedDigest{}
336 } 367 }
337 } 368 }
338 } 369 }
339 370
340 return &GUITestDetails{ 371 return &GUITestDetails{
341 » » Commits: a.currentTestDetails.Commits, 372 » » Commits: a.current.TestDetails.Commits,
342 » » CommitsByDigest: map[string]map[string][]int{testName: a.current TestDetails.CommitsByDigest[testName]}, 373 » » CommitsByDigest: map[string]map[string][]int{testName: a.current .TestDetails.CommitsByDigest[testName]},
343 » » AllParams: a.currentIndex.getAllParams(query), 374 » » AllParams: a.current.Index.getAllParams(query),
344 Query: effectiveQuery, 375 Query: effectiveQuery,
345 Tests: []*GUITestDetail{ 376 Tests: []*GUITestDetail{
346 &GUITestDetail{ 377 &GUITestDetail{
347 Name: testName, 378 Name: testName,
348 Untriaged: untriaged, 379 Untriaged: untriaged,
349 Positive: testDetail.Positive, 380 Positive: testDetail.Positive,
350 Negative: testDetail.Negative, 381 Negative: testDetail.Negative,
351 }, 382 },
352 }, 383 },
353 }, nil 384 }, nil
354 } 385 }
355 386
356 // SetDigestLabels sets the labels for the given digest and records the user 387 // SetDigestLabels sets the labels for the given digest and records the user
357 // that made the classification. 388 // that made the classification.
358 func (a *Analyzer) SetDigestLabels(labeledTestDigests map[string]types.TestClass ification, userId string) (*GUITestDetails, error) { 389 func (a *Analyzer) SetDigestLabels(labeledTestDigests map[string]types.TestClass ification, userId string) (*GUITestDetails, error) {
359 a.mutex.Lock() 390 a.mutex.Lock()
360 defer a.mutex.Unlock() 391 defer a.mutex.Unlock()
361 392
362 expectations, err := a.expStore.Get(true) 393 expectations, err := a.expStore.Get(true)
363 if err != nil { 394 if err != nil {
364 return nil, err 395 return nil, err
365 } 396 }
366 expectations.AddDigests(labeledTestDigests) 397 expectations.AddDigests(labeledTestDigests)
367 if err = a.expStore.Put(expectations, userId); err != nil { 398 if err = a.expStore.Put(expectations, userId); err != nil {
368 return nil, err 399 return nil, err
369 } 400 }
370 401
371 // Let's update our knowledge of the labels. 402 // Let's update our knowledge of the labels.
372 » a.updateDerivedOutputs(labeledTestDigests, expectations) 403 » a.updateDerivedOutputs(labeledTestDigests, expectations, a.current)
404 » a.updateDerivedOutputs(labeledTestDigests, expectations, a.ignored)
373 405
374 result := make([]*GUITestDetail, 0, len(labeledTestDigests)) 406 result := make([]*GUITestDetail, 0, len(labeledTestDigests))
375 for testName := range labeledTestDigests { 407 for testName := range labeledTestDigests {
376 » » result = append(result, a.currentTestDetails.lookup(testName)) 408 » » result = append(result, a.current.TestDetails.lookup(testName))
377 } 409 }
378 410
379 return &GUITestDetails{ 411 return &GUITestDetails{
380 » » Commits: a.currentTestDetails.Commits, 412 » » Commits: a.current.TestDetails.Commits,
381 » » AllParams: a.currentIndex.getAllParams(nil), 413 » » AllParams: a.current.Index.getAllParams(nil),
382 Tests: result, 414 Tests: result,
383 }, nil 415 }, nil
384 } 416 }
385 417
386 func (a *Analyzer) GetStatus() *GUIStatus { 418 func (a *Analyzer) GetStatus() *GUIStatus {
387 » return a.currentStatus 419 » return a.current.Status
420 }
421
422 // ListIgnoreRules returns all current ignore rules.
423 func (a *Analyzer) ListIgnoreRules() ([]*types.IgnoreRule, error) {
424 » rules, err := a.ignoreStore.List()
425 » if err != nil {
426 » » return nil, err
427 » }
428
429 » // TODO(stephana): Inject Count and other statistics about the
430 » // ignored traces. This will be based on LabeledTrace.IgnoreRules.
431
432 » return rules, nil
433 }
434
435 // AddIgnoreRule adds a new ignore rule and recalculates the new state of the
436 // system.
437 func (a *Analyzer) AddIgnoreRule(ignoreRule *types.IgnoreRule) error {
438 » if err := a.ignoreStore.Create(ignoreRule); err != nil {
439 » » return err
440 » }
441
442 » a.processTile()
443
444 » return nil
445 }
446
447 // DeleteIgnoreRule deletes the ignore rule and recalculates the state of the
448 // system.
449 func (a *Analyzer) DeleteIgnoreRule(ruleId int, user string) error {
450 » count, err := a.ignoreStore.Delete(ruleId, user)
451 » if err != nil {
452 » » return err
453 » }
454
455 » if count > 0 {
456 » » a.processTile()
457 » }
458
459 » return nil
388 } 460 }
389 461
390 // loop is the main event loop. 462 // loop is the main event loop.
391 func (a *Analyzer) loop(timeBetweenPolls time.Duration) { 463 func (a *Analyzer) loop(timeBetweenPolls time.Duration) {
392 // The number of times we've successfully loaded and processed a tile.
393 runsCounter := metrics.NewRegisteredCounter("analysis.runs", metrics.Def aultRegistry)
394
395 // The number of times an error has ocurred when trying to load a tile.
396 errorTileLoadingCounter := metrics.NewRegisteredCounter("analysis.errors ", metrics.DefaultRegistry)
397
398 processOneTile := func() {
399 glog.Info("Reading tiles ... ")
400
401 // Load the tile and process it.
402 tile, err := a.tileStore.GetModifiable(0, -1)
403 glog.Info("Done reading tiles.")
404
405 if err != nil {
406 glog.Errorf("Error reading tile store: %s\n", err)
407 errorTileLoadingCounter.Inc(1)
408 } else {
409 // Protect the tile and expectations with the write lock .
410 a.mutex.Lock()
411 defer a.mutex.Unlock()
412
413 // Retrieve the current expectations.
414 expectations, err := a.expStore.Get(false)
415 if err != nil {
416 glog.Errorf("Error retrieving expectations: %s", err)
417 return
418 }
419
420 newLabeledTile := a.processTile(tile)
421 a.setDerivedOutputs(newLabeledTile, expectations)
422 }
423 glog.Info("Done processing tiles.")
424 runsCounter.Inc(1)
425 a.loopCounter++
426 }
427
428 // process a tile immediately and then at fixed points in time. 464 // process a tile immediately and then at fixed points in time.
429 » processOneTile() 465 » a.processTile()
430 for _ = range time.Tick(timeBetweenPolls) { 466 for _ = range time.Tick(timeBetweenPolls) {
431 » » processOneTile() 467 » » a.processTile()
432 } 468 }
433 } 469 }
434 470
435 // processTile processes the last two tiles and updates the cannonical and 471 // processTile loads a tile (built by the ingest process) and partitions it
436 // output data structures. 472 // into two labeled tiles one with the traces of interest and the traces we
437 func (a *Analyzer) processTile(tile *ptypes.Tile) *LabeledTile { 473 // are ignoring.
474 func (a *Analyzer) processTile() {
475 » glog.Info("Reading tiles ... ")
476
477 » // Load the tile and process it.
478 » tile, err := a.tileStore.GetModifiable(0, -1)
479 » glog.Info("Done reading tiles.")
480
481 » if err != nil {
482 » » glog.Errorf("Error reading tile store: %s\n", err)
483 » » errorTileLoadingCounter.Inc(1)
484 » } else {
485 » » // Protect the tile and expectations with the write lock.
486 » » a.mutex.Lock()
487 » » defer a.mutex.Unlock()
488
489 » » // Retrieve the current expectations.
490 » » expectations, err := a.expStore.Get(false)
491 » » if err != nil {
492 » » » glog.Errorf("Error retrieving expectations: %s", err)
493 » » » return
494 » » }
495
496 » » newLabeledTile, ignoredLabeledTile := a.partitionRawTile(tile)
497 » » a.setDerivedOutputs(newLabeledTile, expectations, a.current)
498 » » a.setDerivedOutputs(ignoredLabeledTile, expectations, a.ignored)
499 » }
500 » glog.Info("Done processing tiles.")
501 » runsCounter.Inc(1)
502 » a.loopCounter++
503 }
504
505 // partitionRawTile partitions the input tile into two tiles (current and ignore d)
506 // and derives the output data structures for both.
507 func (a *Analyzer) partitionRawTile(tile *ptypes.Tile) (*LabeledTile, *LabeledTi le) {
438 glog.Info("Processing tile into LabeledTile ...") 508 glog.Info("Processing tile into LabeledTile ...")
439 result := NewLabeledTile()
440 509
510 // Shared between both tiles.
441 tileLen := tile.LastCommitIndex() + 1 511 tileLen := tile.LastCommitIndex() + 1
442 result.Commits = tile.Commits[:tileLen]
443 commitsByDigestMap := map[string]map[string]map[int]bool{}
444 512
445 » ignorableDigests := a.diffStore.IgnorableDigests() 513 » // Set the up the result tile and a tile for ignored traces.
446 » glog.Infof("Ignorable digests: %v", ignorableDigests) 514 » resultTile := NewLabeledTile()
515 » resultTile.Commits = tile.Commits[:tileLen]
516 » resultCommitsByDigestMap := map[string]map[string]map[int]bool{}
517
518 » ignoredTile := NewLabeledTile()
519 » ignoredTile.Commits = tile.Commits[:tileLen]
520 » ignoredCommitsByDigestMap := map[string]map[string]map[int]bool{}
521
522 » // Get the digests that are unavailable, e.g. they cannot be fetched
523 » // from GS or they are not valid images.
524 » unavailableDigests := a.diffStore.UnavailableDigests()
525 » glog.Infof("Unavailable digests: %v", unavailableDigests)
526
527 » // Get the rule matcher to find traces to ignore.
528 » ruleMatcher, err := a.ignoreStore.BuildRuleMatcher()
529 » if err != nil {
530 » » glog.Errorf("Unable to build rule matcher: %s", err)
531 » }
447 532
448 // Note: We are assumming that the number and order of traces will chang e 533 // Note: We are assumming that the number and order of traces will chang e
449 // over time. 534 // over time.
535 var targetTile *LabeledTile
536 var commitsByDigestMap map[string]map[string]map[int]bool
450 for _, v := range tile.Traces { 537 for _, v := range tile.Traces {
538 // Determine if this tile is to be in the result or the ignored tile.
539 matchedRules, isIgnored := ruleMatcher(v.Params())
540 if isIgnored {
541 targetTile = ignoredTile
542 commitsByDigestMap = ignoredCommitsByDigestMap
543 } else {
544 targetTile = resultTile
545 commitsByDigestMap = resultCommitsByDigestMap
546 }
547
451 tempCommitIds := make([]int, 0, tileLen) 548 tempCommitIds := make([]int, 0, tileLen)
452 tempLabels := make([]types.Label, 0, tileLen) 549 tempLabels := make([]types.Label, 0, tileLen)
453 tempDigests := make([]string, 0, tileLen) 550 tempDigests := make([]string, 0, tileLen)
454 gTrace := v.(*ptypes.GoldenTrace) 551 gTrace := v.(*ptypes.GoldenTrace)
455 testName := gTrace.Params()[types.PRIMARY_KEY_FIELD] 552 testName := gTrace.Params()[types.PRIMARY_KEY_FIELD]
456 553
457 // Iterate over the digests in this trace. 554 // Iterate over the digests in this trace.
458 for i, v := range gTrace.Values[:tileLen] { 555 for i, v := range gTrace.Values[:tileLen] {
459 » » » if (v != ptypes.MISSING_DIGEST) && !ignorableDigests[v] { 556 » » » if (v != ptypes.MISSING_DIGEST) && !unavailableDigests[v ] {
460 tempCommitIds = append(tempCommitIds, i) 557 tempCommitIds = append(tempCommitIds, i)
461 tempDigests = append(tempDigests, v) 558 tempDigests = append(tempDigests, v)
462 tempLabels = append(tempLabels, types.UNTRIAGED) 559 tempLabels = append(tempLabels, types.UNTRIAGED)
463 560
464 // Keep track of the commits by digest. 561 // Keep track of the commits by digest.
465 if _, ok := commitsByDigestMap[testName]; !ok { 562 if _, ok := commitsByDigestMap[testName]; !ok {
466 commitsByDigestMap[testName] = map[strin g]map[int]bool{v: map[int]bool{i: true}} 563 commitsByDigestMap[testName] = map[strin g]map[int]bool{v: map[int]bool{i: true}}
467 } else if _, ok := commitsByDigestMap[testName][ v]; !ok { 564 } else if _, ok := commitsByDigestMap[testName][ v]; !ok {
468 commitsByDigestMap[testName][v] = map[in t]bool{i: true} 565 commitsByDigestMap[testName][v] = map[in t]bool{i: true}
469 } else { 566 } else {
470 commitsByDigestMap[testName][v][i] = tru e 567 commitsByDigestMap[testName][v][i] = tru e
471 } 568 }
472 } 569 }
473 } 570 }
474 571
475 // Only consider traces that are not empty. 572 // Only consider traces that are not empty.
476 if len(tempLabels) > 0 { 573 if len(tempLabels) > 0 {
477 // Label the digests and add them to the labeled traces. 574 // Label the digests and add them to the labeled traces.
478 » » » _, targetLabeledTrace := result.getLabeledTrace(v) 575 » » » _, targetLabeledTrace := targetTile.getLabeledTrace(v)
479 targetLabeledTrace.addLabeledDigests(tempCommitIds, temp Digests, tempLabels) 576 targetLabeledTrace.addLabeledDigests(tempCommitIds, temp Digests, tempLabels)
577 if isIgnored {
578 targetLabeledTrace.addIgnoreRules(matchedRules)
579 }
480 } 580 }
481 } 581 }
482 582
583 getCommitsByDigest(resultTile, resultCommitsByDigestMap)
584 getCommitsByDigest(ignoredTile, ignoredCommitsByDigestMap)
585
586 glog.Info("Done processing tile into LabeledTile.")
587 return resultTile, ignoredTile
588 }
589
590 func getCommitsByDigest(labeledTile *LabeledTile, commitsByDigestMap map[string] map[string]map[int]bool) {
483 for testName, cbd := range commitsByDigestMap { 591 for testName, cbd := range commitsByDigestMap {
484 » » result.CommitsByDigest[testName] = make(map[string][]int, len(cb d)) 592 » » labeledTile.CommitsByDigest[testName] = make(map[string][]int, l en(cbd))
485 for d, commitIds := range cbd { 593 for d, commitIds := range cbd {
486 » » » result.CommitsByDigest[testName][d] = util.KeysOfIntSet( commitIds) 594 » » » labeledTile.CommitsByDigest[testName][d] = util.KeysOfIn tSet(commitIds)
487 » » » sort.Ints(result.CommitsByDigest[testName][d]) 595 » » » sort.Ints(labeledTile.CommitsByDigest[testName][d])
488 } 596 }
489 } 597 }
490
491 glog.Info("Done processing tile into LabeledTile.")
492 return result
493 } 598 }
494 599
495 // setDerivedOutputs derives the output data from the given tile and 600 // setDerivedOutputs derives the output data from the given tile and
496 // updates the outputs and tile in the analyzer. 601 // updates the outputs and tile in the analyzer.
497 func (a *Analyzer) setDerivedOutputs(labeledTile *LabeledTile, expectations *exp storage.Expectations) { 602 func (a *Analyzer) setDerivedOutputs(labeledTile *LabeledTile, expectations *exp storage.Expectations, state *AnalyzeState) {
498 // Assign all the labels. 603 // Assign all the labels.
499 for testName, traces := range labeledTile.Traces { 604 for testName, traces := range labeledTile.Traces {
500 for _, trace := range traces { 605 for _, trace := range traces {
501 » » » a.labelDigests(testName, trace.Digests, trace.Labels, ex pectations) 606 » » » labelDigests(testName, trace.Digests, trace.Labels, expe ctations)
502 } 607 }
503 } 608 }
504 609
505 // Generate the lookup index for the tile and get all parameters. 610 // Generate the lookup index for the tile and get all parameters.
506 » a.currentIndex = NewLabeledTileIndex(labeledTile) 611 » state.Index = NewLabeledTileIndex(labeledTile)
507 612
508 // calculate all the output data. 613 // calculate all the output data.
509 » a.currentTile = labeledTile 614 » state.Tile = labeledTile
510 » a.currentTileCounts = a.getOutputCounts(labeledTile) 615 » state.TileCounts = a.getOutputCounts(state.Tile, state.Index)
511 » a.currentTestDetails = a.getTestDetails(labeledTile) 616 » state.TestDetails = a.getTestDetails(state)
512 » a.currentStatus = a.calcStatus(labeledTile) 617 » state.Status = calcStatus(state)
513 } 618 }
514 619
515 // updateLabels iterates over the traces in of the tiles that have changed and 620 // updateLabels iterates over the traces in of the tiles that have changed and
516 // labels them according to our current expecatations. 621 // labels them according to our current expecatations.
517 622
518 // updateDerivedOutputs 623 // updateDerivedOutputs
519 func (a *Analyzer) updateDerivedOutputs(labeledTestDigests map[string]types.Test Classification, expectations *expstorage.Expectations) { 624 func (a *Analyzer) updateDerivedOutputs(labeledTestDigests map[string]types.Test Classification, expectations *expstorage.Expectations, state *AnalyzeState) {
520 // Update the labels of the traces that have changed. 625 // Update the labels of the traces that have changed.
521 for testName := range labeledTestDigests { 626 for testName := range labeledTestDigests {
522 » » if traces, ok := a.currentTile.Traces[testName]; ok { 627 » » if traces, ok := state.Tile.Traces[testName]; ok {
523 for _, trace := range traces { 628 for _, trace := range traces {
524 // Note: This is potentially slower than using l abels in 629 // Note: This is potentially slower than using l abels in
525 // labeledTestDigests directly, but it keeps the code simpler. 630 // labeledTestDigests directly, but it keeps the code simpler.
526 » » » » a.labelDigests(testName, trace.Digests, trace.La bels, expectations) 631 » » » » labelDigests(testName, trace.Digests, trace.Labe ls, expectations)
527 } 632 }
528 } 633 }
529 } 634 }
530 635
531 // Update all the output data structures. 636 // Update all the output data structures.
532 // TODO(stephana): Evaluate whether the counts are really useful or if t hey can be removed. 637 // TODO(stephana): Evaluate whether the counts are really useful or if t hey can be removed.
533 // If we need them uncomment the following line and implement the corres ponding function. 638 // If we need them uncomment the following line and implement the corres ponding function.
534 //a.updateOutputCounts(labeledTestDigests) 639 //a.updateOutputCounts(labeledTestDigests)
535 640
536 // Update the tests that have changed and the status. 641 // Update the tests that have changed and the status.
537 » a.updateTestDetails(labeledTestDigests) 642 » a.updateTestDetails(labeledTestDigests, state)
538 » a.currentStatus = a.calcStatus(a.currentTile) 643 » state.Status = calcStatus(state)
539 } 644 }
540 645
541 // labelDigest assignes a label to the given digests based on the expectations. 646 // labelDigest assignes a label to the given digests based on the expectations.
542 // Its assumes that targetLabels are pre-initialized, usualy with UNTRIAGED, 647 // Its assumes that targetLabels are pre-initialized, usualy with UNTRIAGED,
543 // because it will not change the label if the given test and digest cannot be 648 // because it will not change the label if the given test and digest cannot be
544 // found. 649 // found.
545 func (a *Analyzer) labelDigests(testName string, digests []string, targetLabels []types.Label, expectations *expstorage.Expectations) { 650 func labelDigests(testName string, digests []string, targetLabels []types.Label, expectations *expstorage.Expectations) {
546 for idx, digest := range digests { 651 for idx, digest := range digests {
547 if test, ok := expectations.Tests[testName]; ok { 652 if test, ok := expectations.Tests[testName]; ok {
548 if foundLabel, ok := test[digest]; ok { 653 if foundLabel, ok := test[digest]; ok {
549 targetLabels[idx] = foundLabel 654 targetLabels[idx] = foundLabel
550 } 655 }
551 } 656 }
552 } 657 }
553 } 658 }
554 659
555 // getUntriagedTestDetails returns the untriaged digests of a specific test that 660 // getUntriagedTestDetails returns the untriaged digests of a specific test that
556 // match the given query. In addition to the digests it returns the query 661 // match the given query. In addition to the digests it returns the query
557 // that was used to retrieve them. 662 // that was used to retrieve them.
558 func (a *Analyzer) getUntriagedTestDetails(query, effectiveQuery map[string][]st ring, includeAllTests bool) map[string]map[string]*GUIUntriagedDigest { 663 func (a *Analyzer) getUntriagedTestDetails(query, effectiveQuery map[string][]st ring, includeAllTests bool) map[string]map[string]*GUIUntriagedDigest {
559 » traces, startCommitId, endCommitId, showHead := a.currentIndex.query(que ry, effectiveQuery) 664 » traces, startCommitId, endCommitId, showHead := a.current.Index.query(qu ery, effectiveQuery)
560 endCommitId++ 665 endCommitId++
561 666
562 if len(effectiveQuery) == 0 { 667 if len(effectiveQuery) == 0 {
563 return nil 668 return nil
564 } 669 }
565 670
566 » ret := make(map[string]map[string]*GUIUntriagedDigest, len(a.currentTest Details.Tests)) 671 » ret := make(map[string]map[string]*GUIUntriagedDigest, len(a.current.Tes tDetails.Tests))
567 672
568 // This includes an empty list for tests that we have not found. 673 // This includes an empty list for tests that we have not found.
569 if includeAllTests { 674 if includeAllTests {
570 » » for _, testName := range a.currentIndex.getTestNames(query) { 675 » » for _, testName := range a.current.Index.getTestNames(query) {
571 ret[testName] = nil 676 ret[testName] = nil
572 } 677 }
573 } 678 }
574 679
575 if !showHead { 680 if !showHead {
576 for _, trace := range traces { 681 for _, trace := range traces {
577 testName := trace.Params[types.PRIMARY_KEY_FIELD] 682 testName := trace.Params[types.PRIMARY_KEY_FIELD]
578 » » » current := a.currentTestDetails.lookup(testName).Untriag ed 683 » » » current := a.current.TestDetails.lookup(testName).Untria ged
579 684
580 startIdx := sort.SearchInts(trace.CommitIds, startCommit Id) 685 startIdx := sort.SearchInts(trace.CommitIds, startCommit Id)
581 endIdx := sort.SearchInts(trace.CommitIds, endCommitId) 686 endIdx := sort.SearchInts(trace.CommitIds, endCommitId)
582 if (endIdx < len(trace.CommitIds)) && (trace.CommitIds[e ndIdx] == endCommitId) { 687 if (endIdx < len(trace.CommitIds)) && (trace.CommitIds[e ndIdx] == endCommitId) {
583 endIdx++ 688 endIdx++
584 } 689 }
585 690
586 for idx := startIdx; idx < endIdx; idx++ { 691 for idx := startIdx; idx < endIdx; idx++ {
587 if trace.Labels[idx] == types.UNTRIAGED { 692 if trace.Labels[idx] == types.UNTRIAGED {
588 if found, ok := ret[testName]; !ok || fo und == nil { 693 if found, ok := ret[testName]; !ok || fo und == nil {
589 ret[testName] = make(map[string] *GUIUntriagedDigest, len(current)) 694 ret[testName] = make(map[string] *GUIUntriagedDigest, len(current))
590 } 695 }
591 ret[testName][trace.Digests[idx]] = curr ent[trace.Digests[idx]] 696 ret[testName][trace.Digests[idx]] = curr ent[trace.Digests[idx]]
592 } 697 }
593 } 698 }
594 } 699 }
595 } else { 700 } else {
596 for _, trace := range traces { 701 for _, trace := range traces {
597 lastIdx := len(trace.Labels) - 1 702 lastIdx := len(trace.Labels) - 1
598 if (lastIdx >= 0) && (trace.Labels[lastIdx] == types.UNT RIAGED) { 703 if (lastIdx >= 0) && (trace.Labels[lastIdx] == types.UNT RIAGED) {
599 testName := trace.Params[types.PRIMARY_KEY_FIELD ] 704 testName := trace.Params[types.PRIMARY_KEY_FIELD ]
600 » » » » current := a.currentTestDetails.lookup(testName) .Untriaged 705 » » » » current := a.current.TestDetails.lookup(testName ).Untriaged
601 if found, ok := ret[testName]; !ok || found == n il { 706 if found, ok := ret[testName]; !ok || found == n il {
602 ret[testName] = map[string]*GUIUntriaged Digest{} 707 ret[testName] = map[string]*GUIUntriaged Digest{}
603 } 708 }
604 ret[testName][trace.Digests[lastIdx]] = current[ trace.Digests[lastIdx]] 709 ret[testName][trace.Digests[lastIdx]] = current[ trace.Digests[lastIdx]]
605 } 710 }
606 } 711 }
607 } 712 }
608 713
609 return ret 714 return ret
610 } 715 }
611 716
612 // getSubTile queries the index and returns a LabeledTile that contains the 717 // getSubTile queries the index and returns a LabeledTile that contains the
613 // set of found traces. It also returns the subset of 'query' that contained 718 // set of found traces. It also returns the subset of 'query' that contained
614 // valid parameters and values. 719 // valid parameters and values.
615 // If the returned query is empty the first return value is set to Nil, 720 // If the returned query is empty the first return value is set to Nil,
616 // because now valid filter parameters were found in the query. 721 // because now valid filter parameters were found in the query.
617 func (a *Analyzer) getSubTile(query map[string][]string) (*LabeledTile, map[stri ng][]string) { 722 func (a *Analyzer) getSubTile(query map[string][]string) (*LabeledTile, map[stri ng][]string) {
618 // TODO(stephana): Use the commitStart and commitEnd return values 723 // TODO(stephana): Use the commitStart and commitEnd return values
619 // if we really need this method. GetTileCounts and getSubTile might be 724 // if we really need this method. GetTileCounts and getSubTile might be
620 // removed. 725 // removed.
621 effectiveQuery := make(map[string][]string, len(query)) 726 effectiveQuery := make(map[string][]string, len(query))
622 » traces, _, _, _ := a.currentIndex.query(query, effectiveQuery) 727 » traces, _, _, _ := a.current.Index.query(query, effectiveQuery)
623 if len(effectiveQuery) == 0 { 728 if len(effectiveQuery) == 0 {
624 return nil, effectiveQuery 729 return nil, effectiveQuery
625 } 730 }
626 731
627 result := NewLabeledTile() 732 result := NewLabeledTile()
628 » result.Commits = a.currentTile.Commits 733 » result.Commits = a.current.Tile.Commits
629 734
630 result.Traces = map[string][]*LabeledTrace{} 735 result.Traces = map[string][]*LabeledTrace{}
631 for _, t := range traces { 736 for _, t := range traces {
632 testName := t.Params[types.PRIMARY_KEY_FIELD] 737 testName := t.Params[types.PRIMARY_KEY_FIELD]
633 if _, ok := result.Traces[testName]; !ok { 738 if _, ok := result.Traces[testName]; !ok {
634 result.Traces[testName] = []*LabeledTrace{} 739 result.Traces[testName] = []*LabeledTrace{}
635 } 740 }
636 result.Traces[testName] = append(result.Traces[testName], t) 741 result.Traces[testName] = append(result.Traces[testName], t)
637 } 742 }
638 743
639 return result, effectiveQuery 744 return result, effectiveQuery
640 } 745 }
641 746
642 // getOutputCounts derives the output counts from the given labeled tile. 747 // getOutputCounts derives the output counts from the given labeled tile.
643 func (a *Analyzer) getOutputCounts(labeledTile *LabeledTile) *GUITileCounts { 748 func (a *Analyzer) getOutputCounts(labeledTile *LabeledTile, index *LabeledTileI ndex) *GUITileCounts {
644 glog.Info("Starting to process output counts.") 749 glog.Info("Starting to process output counts.")
645 // Stores the aggregated counts of a tile for each test. 750 // Stores the aggregated counts of a tile for each test.
646 tileCountsMap := make(map[string]*LabelCounts, len(labeledTile.Traces)) 751 tileCountsMap := make(map[string]*LabelCounts, len(labeledTile.Traces))
647 752
648 // Overall aggregated counts over all tests. 753 // Overall aggregated counts over all tests.
649 overallAggregates := newLabelCounts(len(labeledTile.Commits)) 754 overallAggregates := newLabelCounts(len(labeledTile.Commits))
650 755
651 updateCounts(labeledTile, tileCountsMap, overallAggregates) 756 updateCounts(labeledTile, tileCountsMap, overallAggregates)
652 757
653 // TODO (stephana): Factor out human.FlotTickMarks and move it from 758 // TODO (stephana): Factor out human.FlotTickMarks and move it from
654 // perf to the shared go library. 759 // perf to the shared go library.
655 // Generate the tickmarks for the commits. 760 // Generate the tickmarks for the commits.
656 ts := make([]int64, 0, len(labeledTile.Commits)) 761 ts := make([]int64, 0, len(labeledTile.Commits))
657 for _, c := range labeledTile.Commits { 762 for _, c := range labeledTile.Commits {
658 if c.CommitTime != 0 { 763 if c.CommitTime != 0 {
659 ts = append(ts, c.CommitTime) 764 ts = append(ts, c.CommitTime)
660 } 765 }
661 } 766 }
662 767
663 tileCounts := &GUITileCounts{ 768 tileCounts := &GUITileCounts{
664 Commits: labeledTile.Commits, 769 Commits: labeledTile.Commits,
665 Ticks: human.FlotTickMarks(ts), 770 Ticks: human.FlotTickMarks(ts),
666 Aggregated: overallAggregates, 771 Aggregated: overallAggregates,
667 Counts: tileCountsMap, 772 Counts: tileCountsMap,
668 » » AllParams: a.currentIndex.getAllParams(nil), 773 » » AllParams: index.getAllParams(nil),
669 } 774 }
670 775
671 glog.Info("Done processing output counts.") 776 glog.Info("Done processing output counts.")
672 777
673 return tileCounts 778 return tileCounts
674 } 779 }
675 780
676 func updateCounts(labeledTile *LabeledTile, tileCountsMap map[string]*LabelCount s, overallAggregates *LabelCounts) { 781 func updateCounts(labeledTile *LabeledTile, tileCountsMap map[string]*LabelCount s, overallAggregates *LabelCounts) {
677 for testName, testTraces := range labeledTile.Traces { 782 for testName, testTraces := range labeledTile.Traces {
678 acc := newLabelCounts(len(labeledTile.Commits)) 783 acc := newLabelCounts(len(labeledTile.Commits))
(...skipping 14 matching lines...) Expand all
693 tileCountsMap[testName] = acc 798 tileCountsMap[testName] = acc
694 799
695 // Add the aggregates fro this test to the overall aggregates. 800 // Add the aggregates fro this test to the overall aggregates.
696 for idx, u := range acc.Unt { 801 for idx, u := range acc.Unt {
697 overallAggregates.Unt[idx] += u 802 overallAggregates.Unt[idx] += u
698 overallAggregates.Pos[idx] += acc.Pos[idx] 803 overallAggregates.Pos[idx] += acc.Pos[idx]
699 overallAggregates.Neg[idx] += acc.Neg[idx] 804 overallAggregates.Neg[idx] += acc.Neg[idx]
700 } 805 }
701 } 806 }
702 } 807 }
OLDNEW
« no previous file with comments | « golden/Makefile ('k') | golden/go/analysis/analysis_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698