Chromium Code Reviews| 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 |