OLD | NEW |
---|---|
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 | |
jcgregorio
2015/01/30 17:37:28
This doesn't look like it's used anywhere.
stephana
2015/01/30 20:27:45
It's used below by addIgnoreRules. It's not used i
| |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 » // for _, r := range rules { | |
jcgregorio
2015/01/30 17:37:28
commented out ?
stephana
2015/01/30 20:27:45
Added TODO.
| |
430 » // » r.Count = a.ignored.currentIgnoreCounts[r.ID] | |
431 » // } | |
432 | |
433 » return rules, nil | |
434 } | |
435 | |
436 // AddIgnoreRule adds a new ignore rule and recalculates the new state of the | |
437 // system. | |
438 func (a *Analyzer) AddIgnoreRule(ignoreRule *types.IgnoreRule) error { | |
439 » if err := a.ignoreStore.Create(ignoreRule); err != nil { | |
440 » » return err | |
441 » } | |
442 | |
443 » a.processTile() | |
444 | |
445 » return nil | |
446 } | |
447 | |
448 // DeleteIgnoreRule delets the ignore rule and recalculates the state of the | |
jcgregorio
2015/01/30 17:37:28
deletes
stephana
2015/01/30 20:27:45
Done.
| |
449 // system. | |
450 func (a *Analyzer) DeleteIgnoreRule(ruleId int, user string) error { | |
451 » count, err := a.ignoreStore.Delete(ruleId, user) | |
452 » if err != nil { | |
453 » » return err | |
454 » } | |
455 | |
456 » if count > 0 { | |
457 » » a.processTile() | |
458 » } | |
459 | |
460 » return nil | |
388 } | 461 } |
389 | 462 |
390 // loop is the main event loop. | 463 // loop is the main event loop. |
391 func (a *Analyzer) loop(timeBetweenPolls time.Duration) { | 464 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. | 465 // process a tile immediately and then at fixed points in time. |
429 » processOneTile() | 466 » a.processTile() |
430 for _ = range time.Tick(timeBetweenPolls) { | 467 for _ = range time.Tick(timeBetweenPolls) { |
431 » » processOneTile() | 468 » » a.processTile() |
432 } | 469 } |
433 } | 470 } |
434 | 471 |
435 // processTile processes the last two tiles and updates the cannonical and | 472 // processTile loads a tile (built by the ingest process) and partitions it |
436 // output data structures. | 473 // into two labeled tiles one with the traces of interest and the traces we |
437 func (a *Analyzer) processTile(tile *ptypes.Tile) *LabeledTile { | 474 // are ignoring. |
475 func (a *Analyzer) processTile() { | |
476 » glog.Info("Reading tiles ... ") | |
477 | |
478 » // Load the tile and process it. | |
479 » tile, err := a.tileStore.GetModifiable(0, -1) | |
480 » glog.Info("Done reading tiles.") | |
481 | |
482 » if err != nil { | |
483 » » glog.Errorf("Error reading tile store: %s\n", err) | |
484 » » errorTileLoadingCounter.Inc(1) | |
485 » } else { | |
486 » » // Protect the tile and expectations with the write lock. | |
487 » » a.mutex.Lock() | |
488 » » defer a.mutex.Unlock() | |
489 | |
490 » » // Retrieve the current expectations. | |
491 » » expectations, err := a.expStore.Get(false) | |
492 » » if err != nil { | |
493 » » » glog.Errorf("Error retrieving expectations: %s", err) | |
494 » » » return | |
495 » » } | |
496 | |
497 » » newLabeledTile, ignoredLabeledTile := a.partitionRawTile(tile) | |
498 » » a.setDerivedOutputs(newLabeledTile, expectations, a.current) | |
499 » » a.setDerivedOutputs(ignoredLabeledTile, expectations, a.ignored) | |
500 » } | |
501 » glog.Info("Done processing tiles.") | |
502 » runsCounter.Inc(1) | |
503 » a.loopCounter++ | |
504 } | |
505 | |
506 // partitionRawTile partitions the input tile into two tiles (current and ignore d) | |
507 // and derives the output data structures for both. | |
508 func (a *Analyzer) partitionRawTile(tile *ptypes.Tile) (*LabeledTile, *LabeledTi le) { | |
438 glog.Info("Processing tile into LabeledTile ...") | 509 glog.Info("Processing tile into LabeledTile ...") |
439 result := NewLabeledTile() | |
440 | 510 |
511 // Shared between both tiles. | |
441 tileLen := tile.LastCommitIndex() + 1 | 512 tileLen := tile.LastCommitIndex() + 1 |
442 result.Commits = tile.Commits[:tileLen] | |
443 commitsByDigestMap := map[string]map[string]map[int]bool{} | |
444 | 513 |
445 » ignorableDigests := a.diffStore.IgnorableDigests() | 514 » // Set the up the result tile and a tile for ignored traces. |
446 » glog.Infof("Ignorable digests: %v", ignorableDigests) | 515 » resultTile := NewLabeledTile() |
516 » resultTile.Commits = tile.Commits[:tileLen] | |
517 » resultCommitsByDigestMap := map[string]map[string]map[int]bool{} | |
518 | |
519 » ignoredTile := NewLabeledTile() | |
520 » ignoredTile.Commits = tile.Commits[:tileLen] | |
521 » ignoredCommitsByDigestMap := map[string]map[string]map[int]bool{} | |
522 | |
523 » // Get the digests that are unavailable, e.g. they cannot be fetched | |
524 » // from GS or they are not valid images. | |
525 » unavailableDigests := a.diffStore.UnavailableDigests() | |
526 » glog.Infof("Unavailable digests: %v", unavailableDigests) | |
527 | |
528 » // Get the rule matcher to find traces to ignore. | |
529 » ruleMatcher, err := a.ignoreStore.BuildRuleMatcher() | |
530 » if err != nil { | |
531 » » glog.Errorf("Unable to build rule matcher: %s", err) | |
532 » } | |
447 | 533 |
448 // Note: We are assumming that the number and order of traces will chang e | 534 // Note: We are assumming that the number and order of traces will chang e |
449 // over time. | 535 // over time. |
536 var targetTile *LabeledTile | |
537 var commitsByDigestMap map[string]map[string]map[int]bool | |
450 for _, v := range tile.Traces { | 538 for _, v := range tile.Traces { |
539 // Determine if this tile is to be in the result or the ignored tile. | |
540 matchedRules, isIgnored := ruleMatcher(v.Params()) | |
541 if isIgnored { | |
542 targetTile = ignoredTile | |
543 commitsByDigestMap = ignoredCommitsByDigestMap | |
544 } else { | |
545 targetTile = resultTile | |
546 commitsByDigestMap = resultCommitsByDigestMap | |
547 } | |
548 | |
451 tempCommitIds := make([]int, 0, tileLen) | 549 tempCommitIds := make([]int, 0, tileLen) |
452 tempLabels := make([]types.Label, 0, tileLen) | 550 tempLabels := make([]types.Label, 0, tileLen) |
453 tempDigests := make([]string, 0, tileLen) | 551 tempDigests := make([]string, 0, tileLen) |
454 gTrace := v.(*ptypes.GoldenTrace) | 552 gTrace := v.(*ptypes.GoldenTrace) |
455 testName := gTrace.Params()[types.PRIMARY_KEY_FIELD] | 553 testName := gTrace.Params()[types.PRIMARY_KEY_FIELD] |
456 | 554 |
457 // Iterate over the digests in this trace. | 555 // Iterate over the digests in this trace. |
458 for i, v := range gTrace.Values[:tileLen] { | 556 for i, v := range gTrace.Values[:tileLen] { |
459 » » » if (v != ptypes.MISSING_DIGEST) && !ignorableDigests[v] { | 557 » » » if (v != ptypes.MISSING_DIGEST) && !unavailableDigests[v ] { |
460 tempCommitIds = append(tempCommitIds, i) | 558 tempCommitIds = append(tempCommitIds, i) |
461 tempDigests = append(tempDigests, v) | 559 tempDigests = append(tempDigests, v) |
462 tempLabels = append(tempLabels, types.UNTRIAGED) | 560 tempLabels = append(tempLabels, types.UNTRIAGED) |
463 | 561 |
464 // Keep track of the commits by digest. | 562 // Keep track of the commits by digest. |
465 if _, ok := commitsByDigestMap[testName]; !ok { | 563 if _, ok := commitsByDigestMap[testName]; !ok { |
466 commitsByDigestMap[testName] = map[strin g]map[int]bool{v: map[int]bool{i: true}} | 564 commitsByDigestMap[testName] = map[strin g]map[int]bool{v: map[int]bool{i: true}} |
467 } else if _, ok := commitsByDigestMap[testName][ v]; !ok { | 565 } else if _, ok := commitsByDigestMap[testName][ v]; !ok { |
468 commitsByDigestMap[testName][v] = map[in t]bool{i: true} | 566 commitsByDigestMap[testName][v] = map[in t]bool{i: true} |
469 } else { | 567 } else { |
470 commitsByDigestMap[testName][v][i] = tru e | 568 commitsByDigestMap[testName][v][i] = tru e |
471 } | 569 } |
472 } | 570 } |
473 } | 571 } |
474 | 572 |
475 // Only consider traces that are not empty. | 573 // Only consider traces that are not empty. |
476 if len(tempLabels) > 0 { | 574 if len(tempLabels) > 0 { |
477 // Label the digests and add them to the labeled traces. | 575 // Label the digests and add them to the labeled traces. |
478 » » » _, targetLabeledTrace := result.getLabeledTrace(v) | 576 » » » _, targetLabeledTrace := targetTile.getLabeledTrace(v) |
479 targetLabeledTrace.addLabeledDigests(tempCommitIds, temp Digests, tempLabels) | 577 targetLabeledTrace.addLabeledDigests(tempCommitIds, temp Digests, tempLabels) |
578 if isIgnored { | |
579 targetLabeledTrace.addIgnoreRules(matchedRules) | |
580 } | |
480 } | 581 } |
481 } | 582 } |
482 | 583 |
584 getCommitsByDigest(resultTile, resultCommitsByDigestMap) | |
585 getCommitsByDigest(ignoredTile, ignoredCommitsByDigestMap) | |
586 | |
587 glog.Info("Done processing tile into LabeledTile.") | |
588 return resultTile, ignoredTile | |
589 } | |
590 | |
591 func getCommitsByDigest(labeledTile *LabeledTile, commitsByDigestMap map[string] map[string]map[int]bool) { | |
483 for testName, cbd := range commitsByDigestMap { | 592 for testName, cbd := range commitsByDigestMap { |
484 » » result.CommitsByDigest[testName] = make(map[string][]int, len(cb d)) | 593 » » labeledTile.CommitsByDigest[testName] = make(map[string][]int, l en(cbd)) |
485 for d, commitIds := range cbd { | 594 for d, commitIds := range cbd { |
486 » » » result.CommitsByDigest[testName][d] = util.KeysOfIntSet( commitIds) | 595 » » » labeledTile.CommitsByDigest[testName][d] = util.KeysOfIn tSet(commitIds) |
487 » » » sort.Ints(result.CommitsByDigest[testName][d]) | 596 » » » sort.Ints(labeledTile.CommitsByDigest[testName][d]) |
488 } | 597 } |
489 } | 598 } |
490 | |
491 glog.Info("Done processing tile into LabeledTile.") | |
492 return result | |
493 } | 599 } |
494 | 600 |
495 // setDerivedOutputs derives the output data from the given tile and | 601 // setDerivedOutputs derives the output data from the given tile and |
496 // updates the outputs and tile in the analyzer. | 602 // updates the outputs and tile in the analyzer. |
497 func (a *Analyzer) setDerivedOutputs(labeledTile *LabeledTile, expectations *exp storage.Expectations) { | 603 func (a *Analyzer) setDerivedOutputs(labeledTile *LabeledTile, expectations *exp storage.Expectations, state *AnalyzeState) { |
498 // Assign all the labels. | 604 // Assign all the labels. |
499 for testName, traces := range labeledTile.Traces { | 605 for testName, traces := range labeledTile.Traces { |
500 for _, trace := range traces { | 606 for _, trace := range traces { |
501 » » » a.labelDigests(testName, trace.Digests, trace.Labels, ex pectations) | 607 » » » labelDigests(testName, trace.Digests, trace.Labels, expe ctations) |
502 } | 608 } |
503 } | 609 } |
504 | 610 |
505 // Generate the lookup index for the tile and get all parameters. | 611 // Generate the lookup index for the tile and get all parameters. |
506 » a.currentIndex = NewLabeledTileIndex(labeledTile) | 612 » state.Index = NewLabeledTileIndex(labeledTile) |
507 | 613 |
508 // calculate all the output data. | 614 // calculate all the output data. |
509 » a.currentTile = labeledTile | 615 » state.Tile = labeledTile |
510 » a.currentTileCounts = a.getOutputCounts(labeledTile) | 616 » state.TileCounts = a.getOutputCounts(state.Tile, state.Index) |
511 » a.currentTestDetails = a.getTestDetails(labeledTile) | 617 » state.TestDetails = a.getTestDetails(state) |
512 » a.currentStatus = a.calcStatus(labeledTile) | 618 » state.Status = calcStatus(state) |
513 } | 619 } |
514 | 620 |
515 // updateLabels iterates over the traces in of the tiles that have changed and | 621 // updateLabels iterates over the traces in of the tiles that have changed and |
516 // labels them according to our current expecatations. | 622 // labels them according to our current expecatations. |
517 | 623 |
518 // updateDerivedOutputs | 624 // updateDerivedOutputs |
519 func (a *Analyzer) updateDerivedOutputs(labeledTestDigests map[string]types.Test Classification, expectations *expstorage.Expectations) { | 625 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. | 626 // Update the labels of the traces that have changed. |
521 for testName := range labeledTestDigests { | 627 for testName := range labeledTestDigests { |
522 » » if traces, ok := a.currentTile.Traces[testName]; ok { | 628 » » if traces, ok := state.Tile.Traces[testName]; ok { |
523 for _, trace := range traces { | 629 for _, trace := range traces { |
524 // Note: This is potentially slower than using l abels in | 630 // Note: This is potentially slower than using l abels in |
525 // labeledTestDigests directly, but it keeps the code simpler. | 631 // labeledTestDigests directly, but it keeps the code simpler. |
526 » » » » a.labelDigests(testName, trace.Digests, trace.La bels, expectations) | 632 » » » » labelDigests(testName, trace.Digests, trace.Labe ls, expectations) |
527 } | 633 } |
528 } | 634 } |
529 } | 635 } |
530 | 636 |
531 // Update all the output data structures. | 637 // Update all the output data structures. |
532 // TODO(stephana): Evaluate whether the counts are really useful or if t hey can be removed. | 638 // 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. | 639 // If we need them uncomment the following line and implement the corres ponding function. |
534 //a.updateOutputCounts(labeledTestDigests) | 640 //a.updateOutputCounts(labeledTestDigests) |
535 | 641 |
536 // Update the tests that have changed and the status. | 642 // Update the tests that have changed and the status. |
537 » a.updateTestDetails(labeledTestDigests) | 643 » a.updateTestDetails(labeledTestDigests, state) |
538 » a.currentStatus = a.calcStatus(a.currentTile) | 644 » state.Status = calcStatus(state) |
539 } | 645 } |
540 | 646 |
541 // labelDigest assignes a label to the given digests based on the expectations. | 647 // labelDigest assignes a label to the given digests based on the expectations. |
542 // Its assumes that targetLabels are pre-initialized, usualy with UNTRIAGED, | 648 // 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 | 649 // because it will not change the label if the given test and digest cannot be |
544 // found. | 650 // found. |
545 func (a *Analyzer) labelDigests(testName string, digests []string, targetLabels []types.Label, expectations *expstorage.Expectations) { | 651 func labelDigests(testName string, digests []string, targetLabels []types.Label, expectations *expstorage.Expectations) { |
546 for idx, digest := range digests { | 652 for idx, digest := range digests { |
547 if test, ok := expectations.Tests[testName]; ok { | 653 if test, ok := expectations.Tests[testName]; ok { |
548 if foundLabel, ok := test[digest]; ok { | 654 if foundLabel, ok := test[digest]; ok { |
549 targetLabels[idx] = foundLabel | 655 targetLabels[idx] = foundLabel |
550 } | 656 } |
551 } | 657 } |
552 } | 658 } |
553 } | 659 } |
554 | 660 |
555 // getUntriagedTestDetails returns the untriaged digests of a specific test that | 661 // getUntriagedTestDetails returns the untriaged digests of a specific test that |
556 // match the given query. In addition to the digests it returns the query | 662 // match the given query. In addition to the digests it returns the query |
557 // that was used to retrieve them. | 663 // that was used to retrieve them. |
558 func (a *Analyzer) getUntriagedTestDetails(query, effectiveQuery map[string][]st ring, includeAllTests bool) map[string]map[string]*GUIUntriagedDigest { | 664 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) | 665 » traces, startCommitId, endCommitId, showHead := a.current.Index.query(qu ery, effectiveQuery) |
560 endCommitId++ | 666 endCommitId++ |
561 | 667 |
562 if len(effectiveQuery) == 0 { | 668 if len(effectiveQuery) == 0 { |
563 return nil | 669 return nil |
564 } | 670 } |
565 | 671 |
566 » ret := make(map[string]map[string]*GUIUntriagedDigest, len(a.currentTest Details.Tests)) | 672 » ret := make(map[string]map[string]*GUIUntriagedDigest, len(a.current.Tes tDetails.Tests)) |
567 | 673 |
568 // This includes an empty list for tests that we have not found. | 674 // This includes an empty list for tests that we have not found. |
569 if includeAllTests { | 675 if includeAllTests { |
570 » » for _, testName := range a.currentIndex.getTestNames(query) { | 676 » » for _, testName := range a.current.Index.getTestNames(query) { |
571 ret[testName] = nil | 677 ret[testName] = nil |
572 } | 678 } |
573 } | 679 } |
574 | 680 |
575 if !showHead { | 681 if !showHead { |
576 for _, trace := range traces { | 682 for _, trace := range traces { |
577 testName := trace.Params[types.PRIMARY_KEY_FIELD] | 683 testName := trace.Params[types.PRIMARY_KEY_FIELD] |
578 » » » current := a.currentTestDetails.lookup(testName).Untriag ed | 684 » » » current := a.current.TestDetails.lookup(testName).Untria ged |
579 | 685 |
580 startIdx := sort.SearchInts(trace.CommitIds, startCommit Id) | 686 startIdx := sort.SearchInts(trace.CommitIds, startCommit Id) |
581 endIdx := sort.SearchInts(trace.CommitIds, endCommitId) | 687 endIdx := sort.SearchInts(trace.CommitIds, endCommitId) |
582 if (endIdx < len(trace.CommitIds)) && (trace.CommitIds[e ndIdx] == endCommitId) { | 688 if (endIdx < len(trace.CommitIds)) && (trace.CommitIds[e ndIdx] == endCommitId) { |
583 endIdx++ | 689 endIdx++ |
584 } | 690 } |
585 | 691 |
586 for idx := startIdx; idx < endIdx; idx++ { | 692 for idx := startIdx; idx < endIdx; idx++ { |
587 if trace.Labels[idx] == types.UNTRIAGED { | 693 if trace.Labels[idx] == types.UNTRIAGED { |
588 if found, ok := ret[testName]; !ok || fo und == nil { | 694 if found, ok := ret[testName]; !ok || fo und == nil { |
589 ret[testName] = make(map[string] *GUIUntriagedDigest, len(current)) | 695 ret[testName] = make(map[string] *GUIUntriagedDigest, len(current)) |
590 } | 696 } |
591 ret[testName][trace.Digests[idx]] = curr ent[trace.Digests[idx]] | 697 ret[testName][trace.Digests[idx]] = curr ent[trace.Digests[idx]] |
592 } | 698 } |
593 } | 699 } |
594 } | 700 } |
595 } else { | 701 } else { |
596 for _, trace := range traces { | 702 for _, trace := range traces { |
597 lastIdx := len(trace.Labels) - 1 | 703 lastIdx := len(trace.Labels) - 1 |
598 if (lastIdx >= 0) && (trace.Labels[lastIdx] == types.UNT RIAGED) { | 704 if (lastIdx >= 0) && (trace.Labels[lastIdx] == types.UNT RIAGED) { |
599 testName := trace.Params[types.PRIMARY_KEY_FIELD ] | 705 testName := trace.Params[types.PRIMARY_KEY_FIELD ] |
600 » » » » current := a.currentTestDetails.lookup(testName) .Untriaged | 706 » » » » current := a.current.TestDetails.lookup(testName ).Untriaged |
601 if found, ok := ret[testName]; !ok || found == n il { | 707 if found, ok := ret[testName]; !ok || found == n il { |
602 ret[testName] = map[string]*GUIUntriaged Digest{} | 708 ret[testName] = map[string]*GUIUntriaged Digest{} |
603 } | 709 } |
604 ret[testName][trace.Digests[lastIdx]] = current[ trace.Digests[lastIdx]] | 710 ret[testName][trace.Digests[lastIdx]] = current[ trace.Digests[lastIdx]] |
605 } | 711 } |
606 } | 712 } |
607 } | 713 } |
608 | 714 |
609 return ret | 715 return ret |
610 } | 716 } |
611 | 717 |
612 // getSubTile queries the index and returns a LabeledTile that contains the | 718 // 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 | 719 // set of found traces. It also returns the subset of 'query' that contained |
614 // valid parameters and values. | 720 // valid parameters and values. |
615 // If the returned query is empty the first return value is set to Nil, | 721 // 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. | 722 // because now valid filter parameters were found in the query. |
617 func (a *Analyzer) getSubTile(query map[string][]string) (*LabeledTile, map[stri ng][]string) { | 723 func (a *Analyzer) getSubTile(query map[string][]string) (*LabeledTile, map[stri ng][]string) { |
618 // TODO(stephana): Use the commitStart and commitEnd return values | 724 // TODO(stephana): Use the commitStart and commitEnd return values |
619 // if we really need this method. GetTileCounts and getSubTile might be | 725 // if we really need this method. GetTileCounts and getSubTile might be |
620 // removed. | 726 // removed. |
621 effectiveQuery := make(map[string][]string, len(query)) | 727 effectiveQuery := make(map[string][]string, len(query)) |
622 » traces, _, _, _ := a.currentIndex.query(query, effectiveQuery) | 728 » traces, _, _, _ := a.current.Index.query(query, effectiveQuery) |
623 if len(effectiveQuery) == 0 { | 729 if len(effectiveQuery) == 0 { |
624 return nil, effectiveQuery | 730 return nil, effectiveQuery |
625 } | 731 } |
626 | 732 |
627 result := NewLabeledTile() | 733 result := NewLabeledTile() |
628 » result.Commits = a.currentTile.Commits | 734 » result.Commits = a.current.Tile.Commits |
629 | 735 |
630 result.Traces = map[string][]*LabeledTrace{} | 736 result.Traces = map[string][]*LabeledTrace{} |
631 for _, t := range traces { | 737 for _, t := range traces { |
632 testName := t.Params[types.PRIMARY_KEY_FIELD] | 738 testName := t.Params[types.PRIMARY_KEY_FIELD] |
633 if _, ok := result.Traces[testName]; !ok { | 739 if _, ok := result.Traces[testName]; !ok { |
634 result.Traces[testName] = []*LabeledTrace{} | 740 result.Traces[testName] = []*LabeledTrace{} |
635 } | 741 } |
636 result.Traces[testName] = append(result.Traces[testName], t) | 742 result.Traces[testName] = append(result.Traces[testName], t) |
637 } | 743 } |
638 | 744 |
639 return result, effectiveQuery | 745 return result, effectiveQuery |
640 } | 746 } |
641 | 747 |
642 // getOutputCounts derives the output counts from the given labeled tile. | 748 // getOutputCounts derives the output counts from the given labeled tile. |
643 func (a *Analyzer) getOutputCounts(labeledTile *LabeledTile) *GUITileCounts { | 749 func (a *Analyzer) getOutputCounts(labeledTile *LabeledTile, index *LabeledTileI ndex) *GUITileCounts { |
644 glog.Info("Starting to process output counts.") | 750 glog.Info("Starting to process output counts.") |
645 // Stores the aggregated counts of a tile for each test. | 751 // Stores the aggregated counts of a tile for each test. |
646 tileCountsMap := make(map[string]*LabelCounts, len(labeledTile.Traces)) | 752 tileCountsMap := make(map[string]*LabelCounts, len(labeledTile.Traces)) |
647 | 753 |
648 // Overall aggregated counts over all tests. | 754 // Overall aggregated counts over all tests. |
649 overallAggregates := newLabelCounts(len(labeledTile.Commits)) | 755 overallAggregates := newLabelCounts(len(labeledTile.Commits)) |
650 | 756 |
651 updateCounts(labeledTile, tileCountsMap, overallAggregates) | 757 updateCounts(labeledTile, tileCountsMap, overallAggregates) |
652 | 758 |
653 // TODO (stephana): Factor out human.FlotTickMarks and move it from | 759 // TODO (stephana): Factor out human.FlotTickMarks and move it from |
654 // perf to the shared go library. | 760 // perf to the shared go library. |
655 // Generate the tickmarks for the commits. | 761 // Generate the tickmarks for the commits. |
656 ts := make([]int64, 0, len(labeledTile.Commits)) | 762 ts := make([]int64, 0, len(labeledTile.Commits)) |
657 for _, c := range labeledTile.Commits { | 763 for _, c := range labeledTile.Commits { |
658 if c.CommitTime != 0 { | 764 if c.CommitTime != 0 { |
659 ts = append(ts, c.CommitTime) | 765 ts = append(ts, c.CommitTime) |
660 } | 766 } |
661 } | 767 } |
662 | 768 |
663 tileCounts := &GUITileCounts{ | 769 tileCounts := &GUITileCounts{ |
664 Commits: labeledTile.Commits, | 770 Commits: labeledTile.Commits, |
665 Ticks: human.FlotTickMarks(ts), | 771 Ticks: human.FlotTickMarks(ts), |
666 Aggregated: overallAggregates, | 772 Aggregated: overallAggregates, |
667 Counts: tileCountsMap, | 773 Counts: tileCountsMap, |
668 » » AllParams: a.currentIndex.getAllParams(nil), | 774 » » AllParams: index.getAllParams(nil), |
669 } | 775 } |
670 | 776 |
671 glog.Info("Done processing output counts.") | 777 glog.Info("Done processing output counts.") |
672 | 778 |
673 return tileCounts | 779 return tileCounts |
674 } | 780 } |
675 | 781 |
676 func updateCounts(labeledTile *LabeledTile, tileCountsMap map[string]*LabelCount s, overallAggregates *LabelCounts) { | 782 func updateCounts(labeledTile *LabeledTile, tileCountsMap map[string]*LabelCount s, overallAggregates *LabelCounts) { |
677 for testName, testTraces := range labeledTile.Traces { | 783 for testName, testTraces := range labeledTile.Traces { |
678 acc := newLabelCounts(len(labeledTile.Commits)) | 784 acc := newLabelCounts(len(labeledTile.Commits)) |
(...skipping 14 matching lines...) Expand all Loading... | |
693 tileCountsMap[testName] = acc | 799 tileCountsMap[testName] = acc |
694 | 800 |
695 // Add the aggregates fro this test to the overall aggregates. | 801 // Add the aggregates fro this test to the overall aggregates. |
696 for idx, u := range acc.Unt { | 802 for idx, u := range acc.Unt { |
697 overallAggregates.Unt[idx] += u | 803 overallAggregates.Unt[idx] += u |
698 overallAggregates.Pos[idx] += acc.Pos[idx] | 804 overallAggregates.Pos[idx] += acc.Pos[idx] |
699 overallAggregates.Neg[idx] += acc.Neg[idx] | 805 overallAggregates.Neg[idx] += acc.Neg[idx] |
700 } | 806 } |
701 } | 807 } |
702 } | 808 } |
OLD | NEW |