Commit 5a7725d4 authored by Quentin Smith's avatar Quentin Smith

analysis: show benchstat results

Change-Id: Ic9615556358e0262384a1a2f3acb9e4e6ab98532
Reviewed-on: https://go-review.googlesource.com/35502Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 9181f6a8
...@@ -5,10 +5,13 @@ ...@@ -5,10 +5,13 @@
package app package app
import ( import (
"fmt" "bytes"
"html/template"
"io/ioutil"
"net/http" "net/http"
"sort" "sort"
"golang.org/x/perf/analysis/internal/benchstat"
"golang.org/x/perf/storage/benchfmt" "golang.org/x/perf/storage/benchfmt"
) )
...@@ -64,6 +67,39 @@ func (a *App) compare(w http.ResponseWriter, r *http.Request) { ...@@ -64,6 +67,39 @@ func (a *App) compare(w http.ResponseWriter, r *http.Request) {
q := r.Form.Get("q") q := r.Form.Get("q")
tmpl, err := ioutil.ReadFile("template/compare.html")
if err != nil {
http.Error(w, err.Error(), 500)
return
}
t, err := template.New("main").Parse(string(tmpl))
if err != nil {
http.Error(w, err.Error(), 500)
return
}
data, err := a.compareQuery(q)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := t.Execute(w, data); err != nil {
http.Error(w, err.Error(), 500)
return
}
}
type compareData struct {
Q string
Benchstat template.HTML
Groups []*resultGroup
Labels map[string]bool
}
func (a *App) compareQuery(q string) (*compareData, error) {
// Parse query // Parse query
queries := parseQueryString(q) queries := parseQueryString(q)
...@@ -79,8 +115,7 @@ func (a *App) compare(w http.ResponseWriter, r *http.Request) { ...@@ -79,8 +115,7 @@ func (a *App) compare(w http.ResponseWriter, r *http.Request) {
} }
if err := res.Err(); err != nil { if err := res.Err(); err != nil {
// TODO: If the query is invalid, surface that to the user. // TODO: If the query is invalid, surface that to the user.
http.Error(w, err.Error(), 500) return nil, err
return
} }
groups = append(groups, group) groups = append(groups, group)
} }
...@@ -94,15 +129,28 @@ func (a *App) compare(w http.ResponseWriter, r *http.Request) { ...@@ -94,15 +129,28 @@ func (a *App) compare(w http.ResponseWriter, r *http.Request) {
} }
} }
// TODO: Compute benchstat // Compute benchstat
var buf bytes.Buffer
var results [][]*benchfmt.Result
for _, g := range groups {
results = append(results, g.results)
}
benchstat.Run(&buf, results, &benchstat.Options{
HTML: true,
})
// TODO: Render template. This is just temporary output to confirm the above works. // Render template.
w.Header().Set("Content-Type", "text/plain; charset=utf-8") labels := make(map[string]bool)
for i, g := range groups { for _, g := range groups {
fmt.Fprintf(w, "Group #%d: %d results\n", i, len(g.results)) for k := range g.LabelValues {
for k, vs := range g.labelValues { labels[k] = true
fmt.Fprintf(w, "\t%s: %#v\n", k, vs)
} }
fmt.Fprintf(w, "\n")
} }
data := &compareData{
Q: q,
Benchstat: template.HTML(buf.String()),
Groups: groups,
Labels: labels,
}
return data, nil
} }
...@@ -5,10 +5,14 @@ ...@@ -5,10 +5,14 @@
package app package app
import ( import (
"fmt"
"net/http"
"net/http/httptest"
"reflect" "reflect"
"strings" "strings"
"testing" "testing"
"golang.org/x/perf/storage"
"golang.org/x/perf/storage/benchfmt" "golang.org/x/perf/storage/benchfmt"
) )
...@@ -46,3 +50,61 @@ BenchmarkName 1 ns/op` ...@@ -46,3 +50,61 @@ BenchmarkName 1 ns/op`
} }
} }
} }
// static responses for TestCompareQuery
var compareQueries = map[string]string{
"one": `upload: 1
upload-part: 1
label: value
BenchmarkOne 1 5 ns/op
BenchmarkTwo 1 10 ns/op`,
"two": `upload: 1
upload-part: 2
BenchmarkOne 1 10 ns/op
BenchmarkTwo 1 5 ns/op`,
"onetwo": `upload: 1
upload-part: 1
label: value
BenchmarkOne 1 5 ns/op
BenchmarkTwo 1 10 ns/op
label:
upload-part: 2
BenchmarkOne 1 10 ns/op
BenchmarkTwo 1 5 ns/op`,
}
func TestCompareQuery(t *testing.T) {
// TODO(quentin): This test seems too heavyweight; we are but shouldn't be also testing the storage client -> storage server interaction.
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
t.Errorf("ParseForm = %v", err)
}
q := r.Form.Get("q")
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
fmt.Fprint(w, compareQueries[q])
}))
defer ts.Close()
a := &App{StorageClient: &storage.Client{BaseURL: ts.URL}}
for _, q := range []string{"one vs two", "onetwo"} {
t.Run(q, func(t *testing.T) {
data, err := a.compareQuery(q)
if err != nil {
t.Fatalf("compareQuery failed: %v", err)
}
if have := data.Q; have != q {
t.Errorf("Q = %q, want %q", have, q)
}
if len(data.Groups) != 2 {
t.Errorf("len(Groups) = %d, want 2", len(data.Groups))
}
if len(data.Benchstat) == 0 {
t.Error("len(Benchstat) = 0, want >0")
}
if want := map[string]bool{"upload": true, "upload-part": true, "label": true}; !reflect.DeepEqual(data.Labels, want) {
t.Errorf("Labels = %#v, want %#v", data.Labels, want)
}
})
}
}
<!DOCTYPE html>
<html>
<head>
<title>Performance Result Comparison</title>
</head>
<body>
<div>
<form action="/search">
<input type="text" name="q" value="{{.Q}}" size="120">
<input type="submit" value="Search">
</form>
</div>
<div>
{{.Benchstat}}
</div>
<table>
<tr>
<th>label</th>
{{range $index, $group := .Groups}}
<th>
#{{$index}}
</th>
{{end}}
</tr>
{{range $label, $exists := .Labels}}
<tr>
<th>{{$label}}</th>
{{range $.Groups}}
<td>
{{with index .LabelValues $label}}
[
{{range $value, $exists := .}}
{{printf "%q" $value}}
{{end}}
]
{{end}}
</td>
{{end}}
</tr>
{{end}}
</table>
</body>
</html>
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment