diff --git a/dashboard/app/build/perf_changes.go b/dashboard/app/build/perf_changes.go index 3d930dd514..4abbf1a4dd 100644 --- a/dashboard/app/build/perf_changes.go +++ b/dashboard/app/build/perf_changes.go @@ -207,10 +207,12 @@ func findMetric(c *perfChangesCommit, metric string) *perfChangesMetric { } type uiPerfConfig struct { - Builders []uiPerfConfigElem - Benchmarks []uiPerfConfigElem - Metrics []uiPerfConfigElem - Procs []uiPerfConfigElem + Builders []uiPerfConfigElem + Benchmarks []uiPerfConfigElem + Metrics []uiPerfConfigElem + Procs []uiPerfConfigElem + CommitsFrom []uiPerfConfigElem + CommitsTo []uiPerfConfigElem } type uiPerfConfigElem struct { diff --git a/dashboard/app/build/perf_graph.go b/dashboard/app/build/perf_graph.go index 206ae2173d..647d58777d 100644 --- a/dashboard/app/build/perf_graph.go +++ b/dashboard/app/build/perf_graph.go @@ -36,7 +36,6 @@ func perfGraphHandler(w http.ResponseWriter, r *http.Request) { allMetrics := pc.MetricsForBenchmark("") allProcs := pc.ProcList("") r.ParseForm() - absolute := r.FormValue("absolute") != "" selBuilders := r.Form["builder"] selBenchmarks := r.Form["benchmark"] selMetrics := r.Form["metric"] @@ -53,8 +52,55 @@ func perfGraphHandler(w http.ResponseWriter, r *http.Request) { if len(selProcs) == 0 { selProcs = append(selProcs, "1") } + commitFrom := r.FormValue("commit-from") + if commitFrom == "" { + commitFrom = lastRelease + } + commitTo := r.FormValue("commit-to") + if commitTo == "" { + commitTo = "tip" + } // TODO(dvyukov): validate input + // Figure out start and end commit from commitFrom/commitTo. + startCommitNum := 0 + endCommitNum := 0 + { + comFrom := &Commit{Hash: knownTags[commitFrom]} + if err := datastore.Get(c, comFrom.Key(c), comFrom); err != nil { + logErr(w, r, err) + return + } + startCommitNum = comFrom.Num - 1 + + retry: + if commitTo == "tip" { + p, err := GetPackage(c, "") + if err != nil { + logErr(w, r, err) + return + } + endCommitNum = p.NextNum + } else { + comTo := &Commit{Hash: knownTags[commitTo]} + if err := datastore.Get(c, comTo.Key(c), comTo); err != nil { + logErr(w, r, err) + return + } + endCommitNum = comTo.Num + } + if endCommitNum <= startCommitNum { + // User probably selected from:go1.3 to:go1.2. Fix go1.2 to tip. + if commitTo == "tip" { + logErr(w, r, fmt.Errorf("no commits to display (%v-%v)", commitFrom, commitTo)) + return + } + commitTo = "tip" + goto retry + } + } + commitsToDisplay := endCommitNum - startCommitNum + present := func(set []string, s string) bool { for _, s1 := range set { if s1 == s { @@ -77,43 +123,14 @@ func perfGraphHandler(w http.ResponseWriter, r *http.Request) { for _, v := range allProcs { cfg.Procs = append(cfg.Procs, uiPerfConfigElem{strconv.Itoa(v), present(selProcs, strconv.Itoa(v))}) } - - // Select last commit. - startCommit := 0 - commitsToDisplay := 100 - if r.FormValue("startcommit") != "" { - startCommit, _ = strconv.Atoi(r.FormValue("startcommit")) - commitsToDisplay, _ = strconv.Atoi(r.FormValue("commitnum")) - } else { - var commits1 []*Commit - _, err = datastore.NewQuery("Commit"). - Ancestor((&Package{}).Key(c)). - Order("-Num"). - Filter("NeedsBenchmarking =", true). - Limit(1). - GetAll(c, &commits1) - if err != nil || len(commits1) != 1 { - logErr(w, r, err) - return - } - startCommit = commits1[0].Num + for k := range knownTags { + cfg.CommitsFrom = append(cfg.CommitsFrom, uiPerfConfigElem{k, commitFrom == k}) } - - if r.FormValue("zoomin") != "" { - commitsToDisplay /= 2 - } else if r.FormValue("zoomout") != "" { - commitsToDisplay *= 2 - } else if r.FormValue("older") != "" { - startCommit -= commitsToDisplay / 2 - } else if r.FormValue("newer") != "" { - startCommit += commitsToDisplay / 2 + for k := range knownTags { + cfg.CommitsTo = append(cfg.CommitsTo, uiPerfConfigElem{k, commitTo == k}) } + cfg.CommitsTo = append(cfg.CommitsTo, uiPerfConfigElem{"tip", commitTo == "tip"}) - // TODO(dvyukov): limit number of lines on the graph? - startCommitNum := startCommit - commitsToDisplay + 1 - if startCommitNum < 0 { - startCommitNum = 0 - } var vals [][]float64 var hints [][]string var certainty [][]bool @@ -133,39 +150,13 @@ func perfGraphHandler(w http.ResponseWriter, r *http.Request) { logErr(w, r, err) return } - nonzero := false - min := ^uint64(0) - max := uint64(0) + hasdata := false for _, v := range vv { - if v == 0 { - continue + if v != 0 { + hasdata = true } - if max < v { - max = v - } - if min > v { - min = v - } - nonzero = true } - if nonzero { - noise := pc.NoiseLevel(builder, benchProcs, metric) - diff := (float64(max) - float64(min)) / float64(max) * 100 - // Scale graph passes through 2 points: (noise, minScale) and (growthFactor*noise, 100). - // Plus it's bottom capped at minScale and top capped at 100. - // Intention: - // Diffs below noise are scaled to minScale. - // Diffs above growthFactor*noise are scaled to 100. - // Between noise and growthFactor*noise scale growths linearly. - const minScale = 5 - const growthFactor = 4 - scale := diff*(100-minScale)/(noise*(growthFactor-1)) + (minScale*growthFactor-100)/(growthFactor-1) - if scale < minScale { - scale = minScale - } - if scale > 100 { - scale = 100 - } + if hasdata { descBuilder := "/" + builder descBenchmark := "/" + benchProcs descMetric := "/" + metric @@ -182,6 +173,7 @@ func perfGraphHandler(w http.ResponseWriter, r *http.Request) { hh := make([]string, commitsToDisplay) valf := make([]float64, commitsToDisplay) cert := make([]bool, commitsToDisplay) + firstval := uint64(0) lastval := uint64(0) lastval0 := uint64(0) for i, v := range vv { @@ -204,26 +196,20 @@ func perfGraphHandler(w http.ResponseWriter, r *http.Request) { } cert[i] = false v = lastval + uint64(int64(nextval-lastval)/int64(nextidx-i+1)) - _, _ = nextval, nextidx } - f := float64(v) - if !absolute { - f = (float64(v) - float64(min)) * 100 / (float64(max) - float64(min)) - f = f*scale/100 + (100-scale)/2 - f += 0.000001 + if firstval == 0 { + firstval = v } - valf[i] = f - com := commits2[i] - comLink := "https://code.google.com/p/go/source/detail?r=" + com.Hash + valf[i] = float64(v) / float64(firstval) if cert[i] { d := "" if lastval0 != 0 { d = fmt.Sprintf(" (%.02f%%)", perfDiff(lastval0, v)) } - cmpLink := fmt.Sprintf("/perfdetail?commit=%v&builder=%v&benchmark=%v", com.Hash, builder, benchmark) - hh[i] = fmt.Sprintf("%v: %v%v
%v
%v", desc, cmpLink, v, d, comLink, com.Desc, com.Time.Format("Jan 2, 2006 1:04")) + hh[i] = fmt.Sprintf("%v%v", v, d) + } else { - hh[i] = fmt.Sprintf("%v: NO DATA
%v
%v", desc, comLink, com.Desc, com.Time.Format("Jan 2, 2006 1:04")) + hh[i] = "NO DATA" } lastval = v if cert[i] { @@ -233,7 +219,7 @@ func perfGraphHandler(w http.ResponseWriter, r *http.Request) { vals = append(vals, valf) hints = append(hints, hh) certainty = append(certainty, cert) - headers = append(headers, fmt.Sprintf("%s (%.2f%% [%.2f%%])", desc, diff, noise)) + headers = append(headers, desc) } } } @@ -242,11 +228,14 @@ func perfGraphHandler(w http.ResponseWriter, r *http.Request) { var commits []perfGraphCommit if len(vals) != 0 && len(vals[0]) != 0 { + idx := 0 for i := range vals[0] { - if !commits2[i].NeedsBenchmarking { + com := commits2[i] + if !com.NeedsBenchmarking { continue } - var c perfGraphCommit + c := perfGraphCommit{Id: idx, Name: fmt.Sprintf("%v (%v)", com.Desc, com.Time.Format("Jan 2, 2006 1:04"))} + idx++ for j := range vals { c.Vals = append(c.Vals, perfGraphValue{float64(vals[j][i]), certainty[j][i], hints[j][i]}) } @@ -254,7 +243,7 @@ func perfGraphHandler(w http.ResponseWriter, r *http.Request) { } } - data := &perfGraphData{d, cfg, startCommit, commitsToDisplay, absolute, headers, commits} + data := &perfGraphData{d, cfg, headers, commits} var buf bytes.Buffer if err := perfGraphTemplate.Execute(&buf, data); err != nil { @@ -270,16 +259,14 @@ var perfGraphTemplate = template.Must( ) type perfGraphData struct { - Dashboard *Dashboard - Config *uiPerfConfig - StartCommit int - CommitNum int - Absolute bool - Headers []string - Commits []perfGraphCommit + Dashboard *Dashboard + Config *uiPerfConfig + Headers []string + Commits []perfGraphCommit } type perfGraphCommit struct { + Id int Name string Vals []perfGraphValue } diff --git a/dashboard/app/build/perf_graph.html b/dashboard/app/build/perf_graph.html index c6397b68a1..ab17a274b8 100644 --- a/dashboard/app/build/perf_graph.html +++ b/dashboard/app/build/perf_graph.html @@ -13,15 +13,17 @@ google.setOnLoadCallback(drawCharts); function drawCharts() { var data = new google.visualization.DataTable(); - data.addColumn('string', 'Commit'); + data.addColumn({type: 'number', label: 'Commit'}); + data.addColumn({type: 'number'}); + data.addColumn({type: 'string', role: 'tooltip'}); {{range $.Headers}} - data.addColumn('number', '{{.}}'); + data.addColumn({type: 'number', label: '{{.}}'}); data.addColumn({type: 'boolean', role: 'certainty'}); - data.addColumn({type: 'string', role: 'tooltip', p: {html: true}}); + data.addColumn({type: 'string', role: 'tooltip'}); {{end}} data.addRows([ {{range $.Commits}} - [ '{{.Name}}', + [ {{.Id}}, 1, "{{.Name}}", {{range .Vals}} {{if .Val}} {{.Val}}, {{.Certainty}}, '{{.Hint}}', @@ -35,13 +37,12 @@ new google.visualization.LineChart(document.getElementById('graph_div')). draw(data, { width: "100%", - height: 600, + height: 700, legend: {position: "bottom"}, - tooltip: {isHtml: true}, - {{if not $.Absolute}} - vAxis: {textPosition: "none", ticks: [0,10,20,30,40,50,60,70,80,90,100]}, - {{end}} - chartArea: {left: "10%", top: "5%", width: "85%", height:"85%"} + focusTarget: "category", + hAxis: {textPosition: "none"}, + chartArea: {left: "10%", top: "5%", width: "85%", height:"80%"}, + explorer: {axis: 'horizontal', maxZoomIn: 0, maxZoomOut: 1, zoomDelta: 1.2, keepInBounds: true} }) } @@ -66,48 +67,49 @@

Builders

- {{.Name}}
{{end}} -

Benchmarks

- {{.Name}}
{{end}} -

Procs

- {{.Name}}
{{end}} -

Metrics

- {{.Name}}
+ {{end}} +
+ +
+

Commits

+ From: + + To: +
- absolute scale - - - - - -