// getTraceDBEntries returns a map of tracedb.Entry instances. func (b *BenchData) getTraceDBEntries() map[string]*tracedb.Entry { ret := make(map[string]*tracedb.Entry, len(b.Results)) keyPrefix := b.keyPrefix() for testName, allConfigs := range b.Results { for configName, result := range allConfigs { key := fmt.Sprintf("%s:%s:%s", keyPrefix, testName, configName) // Construct the Traces params from all the options. params := util.CopyStringMap(b.Key) params["test"] = testName params["config"] = configName util.AddParams(params, b.Options) // If there is an options map inside the result add it to the params. if resultOptions, ok := result["options"]; ok { if opts, ok := resultOptions.(map[string]interface{}); ok { for k, vi := range opts { if s, ok := vi.(string); ok { params[k] = s } } } } // We used to just pick out only "min_ms" as the only result of a bunch // of key, value pairs in the result, such as max_ms, mean_ms, etc. Now // nanobench uploads only the metrics we are interested in, so we need to // use all the values there, except 'options'. for k, vi := range result { if k == "options" { continue } floatVal, ok := vi.(float64) if !ok { glog.Errorf("Found a non-float64 in %s", key) continue } params["sub_result"] = k perResultKey := key if k != "min_ms" { perResultKey = fmt.Sprintf("%s:%s", perResultKey, k) } paramsCopy := util.CopyStringMap(params) ret[perResultKey] = &tracedb.Entry{ Params: paramsCopy, Value: types.BytesFromFloat64(floatVal), } } } } return ret }
// searchByIssue searches across the given issue. func searchByIssue(issue string, q *Query, exp *expstorage.Expectations, parsedQuery url.Values, storages *storage.Storage, tile *tiling.Tile, tallies *tally.Tallies, tileParamSet *paramsets.Summary) ([]*Digest, error) { trybotResults, err := storages.TrybotResults.Get(issue) if err != nil { return nil, err } // Get a matcher for the ignore rules if we filter ignores. var ignoreMatcher ignore.RuleMatcher = nil if !q.IncludeIgnores { ignoreMatcher, err = storages.IgnoreStore.BuildRuleMatcher() if err != nil { return nil, fmt.Errorf("Unable to build rules matcher: %s", err) } } // Set up a rule to match the query. var queryRule ignore.QueryRule = nil if len(parsedQuery) > 0 { queryRule = ignore.NewQueryRule(parsedQuery) } // Aggregate the results into an intermediate representation to avoid // passing over the dataset twice. inter := map[string]*issueIntermediate{} talliesByTest := tallies.ByTest() for _, bot := range trybotResults.Bots { for _, result := range bot.TestResults { expandedParams := util.CopyStringMap(bot.BotParams) util.AddParams(expandedParams, result.Params) if ignoreMatcher != nil { if _, ok := ignoreMatcher(expandedParams); ok { continue } } if (queryRule == nil) || queryRule.IsMatch(expandedParams) { testName := expandedParams[types.PRIMARY_KEY_FIELD] digest := trybotResults.Digests[result.DigestIdx] key := testName + ":" + digest if !q.IncludeMaster { if _, ok := talliesByTest[testName][digest]; ok { continue } } if found, ok := inter[key]; ok { found.add(expandedParams) } else if cl := exp.Classification(testName, digest); !q.excludeClassification(cl) { inter[key] = newIssueIntermediate(expandedParams, digest, cl) } } } } // Build the output and make sure the digest are cached on disk. digests := make(map[string]bool, len(inter)) ret := make([]*Digest, 0, len(inter)) emptyTraces := &Traces{} for _, i := range inter { ret = append(ret, &Digest{ Test: i.test, Digest: i.digest, Status: i.status.String(), ParamSet: i.paramSet, Diff: buildDiff(i.test, i.digest, exp, tile, talliesByTest, nil, storages.DiffStore, tileParamSet, q.IncludeIgnores), Traces: emptyTraces, }) digests[i.digest] = true } // This ensures that all digests are cached on disk. storages.DiffStore.AbsPath(util.KeysOfStringSet(digests)) return ret, nil }