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

Unified Diff: perf/server/src/server/perf.go

Issue 382313002: Adds tile handler to the perf server (Closed) Base URL: https://skia.googlesource.com/buildbot.git@master
Patch Set: More style fixes Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: perf/server/src/server/perf.go
diff --git a/perf/server/src/server/perf.go b/perf/server/src/server/perf.go
index 26bd16d3df56456c57efbb4451f826d81c953b47..9a1e370cb1cdd3f2cc04816099d5de6c0ee1409f 100644
--- a/perf/server/src/server/perf.go
+++ b/perf/server/src/server/perf.go
@@ -18,6 +18,7 @@ import (
"regexp"
"sort"
"strconv"
+ "strings"
"time"
)
@@ -30,6 +31,8 @@ import (
import (
"config"
"db"
+ "filetilestore"
+ "types"
)
var (
@@ -47,6 +50,9 @@ var (
clustersHandlerPath = regexp.MustCompile(`/clusters/([a-z]*)$`)
shortcutHandlerPath = regexp.MustCompile(`/shortcuts/([0-9]*)$`)
+
+ // The three capture groups are dataset, tile scale, and tile number
jcgregorio 2014/07/11 20:36:49 and tile number.
kelvinly 2014/07/11 20:51:58 Done.
kelvinly 2014/07/11 20:51:58 Done.
+ tileHandlerPath = regexp.MustCompile(`/tiles/([a-z]*)/([0-9]*)/([-0-9]*)$`)
)
// flags
@@ -59,6 +65,8 @@ var (
var (
data *Data
+
+ tileStores map[string]types.TileStore
)
const (
@@ -87,6 +95,11 @@ func Init() {
indexTemplate = template.Must(template.ParseFiles(filepath.Join(cwd, "templates/index.html")))
index2Template = template.Must(template.ParseFiles(filepath.Join(cwd, "templates/index2.html")))
clusterTemplate = template.Must(template.ParseFiles(filepath.Join(cwd, "templates/clusters.html")))
+
+ tileStores = make(map[string]types.TileStore)
+ for _, name := range config.ALL_DATASET_NAMES {
+ tileStores[string(name)] = filetilestore.NewFileTileStore(*tileDir, string(name))
+ }
}
// reportError formats an HTTP error response and also logs the detailed error message.
@@ -244,6 +257,178 @@ func annotationsHandler(w http.ResponseWriter, r *http.Request) {
}
}
+func makeKeyFromParams(paramList []string, params map[string]string) string {
jcgregorio 2014/07/11 20:36:50 Need docs
kelvinly 2014/07/11 20:51:58 Done.
+ newKey := make([]string, len(paramList))
+ for i, paramName := range paramList {
+ if name, ok := params[paramName]; ok {
+ newKey[i] = name
+ } else {
+ newKey[i] = ""
+ }
+ }
+ return strings.Join(newKey, ":")
+}
+
+func getTile(dataset string, tileScale, tileNumber int) (*types.Tile, error) {
jcgregorio 2014/07/11 20:36:49 Needs docs
kelvinly 2014/07/11 20:51:58 Done.
+ tileStore, ok := tileStores[dataset]
+ if !ok {
+ return nil, fmt.Errorf("Unable to access dataset store for %s", dataset)
+ }
+ tile, err := tileStore.Get(int(tileScale), int(tileNumber))
+ if err != nil || tile == nil {
+ return nil, fmt.Errorf("Unable to get tile from tilestore: ", err)
+ }
+ return tile, nil
+}
+
+// tileHandler accepts URIs like /tiles/skps/0/1?traces=Some:long:trace:here&omit_commits=true
+// where the URI format is /tiles/<dataset-name>/<tile-scale>/<tile-number>
+// It accepts a comma-delimited string of keys as traces, and
+// also omit_commits, omit_traces, and omit_names, which each cause the corresponding
+// section (described more thoroughly in types.go) to be omitted from the JSON
+func tileHandler(w http.ResponseWriter, r *http.Request) {
+ // So this almost doubles the size of this file. Should I move it into its own package?
+ glog.Infof("Tile Handler: %q\n", r.URL.Path)
+ match := tileHandlerPath.FindStringSubmatch(r.URL.Path)
+ if r.Method != "GET" || match == nil || len(match) != 4 {
+ http.NotFound(w, r)
+ return
+ }
+ dataset := match[1]
+ tileScale, err := strconv.ParseInt(match[2], 10, 0)
+ if err != nil {
+ reportError(w, r, err, "Failed parsing tile scale.")
+ return
+ }
+ tileNumber, err := strconv.ParseInt(match[3], 10, 0)
+ if err != nil {
+ reportError(w, r, err, "Failed parsing tile number.")
+ return
+ }
+ // TODO: Use some sort of cache
jcgregorio 2014/07/11 20:36:49 Move the TODO into getTile.
kelvinly 2014/07/11 20:51:58 Done.
+ tile, err := getTile(dataset, int(tileScale), int(tileNumber))
+ if err != nil {
+ reportError(w, r, err, "Failed to retrieve tile.")
+ return
+ }
+ tracesRequested := strings.Split(r.FormValue("traces"), ",")
+ omitCommits := r.FormValue("omit_commits") != ""
+ omitParams := r.FormValue("omit_params") != ""
+ omitNames := r.FormValue("omit_names") != ""
+ result := types.NewGUITile(int(tileScale), int(tileNumber))
+ paramList, ok := config.KEY_PARAM_ORDER[dataset]
+ if !ok {
+ reportError(w, r, err, "Unable to read parameter list for dataset: ")
+ return
+ }
+ for _, keyName := range tracesRequested {
+ if len(keyName) <= 0 {
+ continue
+ }
+ var rawTrace *types.Trace
+ count := 0
+ // Unpack trace name and find the trace.
+ keyParts := strings.Split(keyName, ":")
+ for _, tileTrace := range tile.Traces {
+ tracesMatch := true
+ for i, keyPart := range keyParts {
+ if len(keyPart) > 0 {
+ if traceParam, exists := tileTrace.Params[paramList[i]]; !exists || traceParam != keyPart {
+ tracesMatch = false
+ break
+ }
+ // If it doesn't exist in the key, it should also not exist in
+ // the trace parameters
+ } else if traceParam, exists := tileTrace.Params[paramList[i]]; exists && len(traceParam) <= 0 {
+ tracesMatch = false
+ break
+ }
+ }
+ if tracesMatch {
+ rawTrace = tileTrace
+ // NOTE: Not breaking out of the loop
+ // for now to see if there are multiple
+ // traces that match any given trace
+ count += 1
+ }
+ }
+ // No matches
+ if count <= 0 || rawTrace == nil {
+ continue
+ } else {
+ if count > 1 {
+ glog.Warningln(count, "matches found for ", keyName)
+ }
+ }
+ newTraceData := make([][2]float64, 0)
+ for i, traceVal := range rawTrace.Values {
+ if traceVal != config.MISSING_DATA_SENTINEL {
+ newTraceData = append(newTraceData, [2]float64{
+ traceVal,
+ float64(tile.Commits[i].CommitTime),
+ // We should have 53 significand bits, so this should work correctly basically forever
+ })
+ }
+ }
+ if len(newTraceData) > 0 {
+ result.Traces = append(result.Traces, types.TraceGUI{
+ Data: newTraceData,
+ Key: keyName,
+ })
+ }
+ }
+ if !omitCommits {
+ result.Commits = tile.Commits
+ }
+ if !omitNames {
+ for _, trace := range tile.Traces {
+ result.NameList = append(result.NameList, makeKeyFromParams(paramList, trace.Params))
+ }
+ }
+ if !omitParams {
+ // NOTE: When constructing ParamSet, we need to make sure there are empty strings
+ // where there's at least one key missing that parameter
+ // TODO: Fix this on tile generation rather than here
jcgregorio 2014/07/11 20:36:49 All comments should be complete sentences, modulo
kelvinly 2014/07/11 20:51:58 Done.
+ result.ParamSet = make([][]string, len(paramList))
+ for i := range result.ParamSet {
+ if readableName, ok := config.HUMAN_READABLE_PARAM_NAMES[paramList[i]]; !ok {
+ glog.Warningln(fmt.Sprintf("%s does not exist in the readable parameter names list", paramList[i]))
+ result.ParamSet[i] = []string{paramList[i]}
+ } else {
+ result.ParamSet[i] = []string{readableName}
+ }
+ }
+ for _, trace := range tile.Traces {
+ for i := range result.ParamSet {
+ traceValue, ok := trace.Params[paramList[i]]
+ if !ok {
+ traceValue = ""
+ }
+ traceValueIsInParamSet := false
+ for _, param := range []string(result.ParamSet[i]) {
+ if param == traceValue {
+ traceValueIsInParamSet = true
+ }
+ }
+ if !traceValueIsInParamSet {
+ result.ParamSet[i] = append(result.ParamSet[i], traceValue)
+ }
+ }
+ }
+ }
+ // Marshal and send
+ marshaledResult, err := json.Marshal(result)
+ if err != nil {
+ reportError(w, r, err, "Failed to marshal JSON.")
+ return
+ }
+ w.Header().Set("Content-Type", "application/json")
+ _, err = w.Write(marshaledResult)
+ if err != nil {
+ reportError(w, r, err, "Error while marshalling results.")
+ }
+}
+
// jsonHandler handles the GET for the JSON requests.
func jsonHandler(w http.ResponseWriter, r *http.Request) {
glog.Infof("JSON Handler: %q\n", r.URL.Path)
@@ -306,6 +491,7 @@ func main() {
http.HandleFunc("/index2", autogzip.HandleFunc(main2Handler))
http.HandleFunc("/json/", jsonHandler) // We pre-gzip this ourselves.
http.HandleFunc("/shortcuts/", shortcutHandler)
+ http.HandleFunc("/tiles/", tileHandler)
http.HandleFunc("/clusters/", autogzip.HandleFunc(clusterHandler))
http.HandleFunc("/annotations/", autogzip.HandleFunc(annotationsHandler))

Powered by Google App Engine
This is Rietveld 408576698