Skip to content

Commit 0370ffc

Browse files
mknyszekgopherbot
authored andcommittedNov 18, 2024·
perf: display the geomean time series on the front page
This change does a few things: - Start emitting geomean/<builder details> as a separate time series. - Add the option to mix benchmarks of all platforms on the same page. - Set up the front page to show the geomean for each builder we run. Change-Id: I50bfe0a2f7c92bb7405cf0d799f95c4ec3226a8d Reviewed-on: https://go-review.googlesource.com/c/build/+/627555 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com> Auto-Submit: Michael Knyszek <mknyszek@google.com>
1 parent a21e243 commit 0370ffc

File tree

4 files changed

+215
-120
lines changed

4 files changed

+215
-120
lines changed
 

‎perf/app/dashboard.go

+86-68
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ type DataJSON struct {
6767
type BenchmarkJSON struct {
6868
Name string
6969
Unit string
70+
Platform string
7071
HigherIsBetter bool
7172

7273
// These will be sorted by CommitDate.
@@ -89,11 +90,11 @@ type ValueJSON struct {
8990

9091
// filter is a set of parameters used to filter influx data.
9192
type filter struct {
92-
start, end time.Time
93-
repository string
94-
goos string
95-
goarch string
96-
goBranch string
93+
start, end time.Time // Required.
94+
repository string // Required.
95+
goos string // Optional.
96+
goarch string // Optional.
97+
goBranch string // Required.
9798
}
9899

99100
func fluxRecordToValue(rec *query.FluxRecord) (ValueJSON, error) {
@@ -161,11 +162,15 @@ func fetchNamedUnitBenchmark(ctx context.Context, qc api.QueryAPI, f *filter, na
161162
if err := validateFluxString(f.repository); err != nil {
162163
return nil, fmt.Errorf("invalid repository name: %w", err)
163164
}
164-
if err := validateFluxString(f.goos); err != nil {
165-
return nil, fmt.Errorf("invalid GOOS: %w", err)
165+
if f.goos != "" {
166+
if err := validateFluxString(f.goos); err != nil {
167+
return nil, fmt.Errorf("invalid GOOS: %w", err)
168+
}
166169
}
167-
if err := validateFluxString(f.goarch); err != nil {
168-
return nil, fmt.Errorf("invalid GOOS: %w", err)
170+
if f.goarch != "" {
171+
if err := validateFluxString(f.goarch); err != nil {
172+
return nil, fmt.Errorf("invalid GOOS: %w", err)
173+
}
169174
}
170175
if err := validateFluxString(f.goBranch); err != nil {
171176
return nil, fmt.Errorf("invalid go branch name: %w", err)
@@ -187,13 +192,13 @@ from(bucket: "perf")
187192
|> filter(fn: (r) => r["name"] == "%s")
188193
|> filter(fn: (r) => r["unit"] == "%s")
189194
|> filter(fn: (r) => r["branch"] == "%s")
190-
|> filter(fn: (r) => r["goos"] == "%s")
191-
|> filter(fn: (r) => r["goarch"] == "%s")
195+
|> filter(fn: (r) => ("%s" != "" and r["goos"] == "%s") or "%s" == "")
196+
|> filter(fn: (r) => ("%s" != "" and r["goarch"] == "%s") or "%s" == "")
192197
|> fill(column: "repository", value: "go")
193198
|> filter(fn: (r) => r["repository"] == "%s")
194199
|> pivot(columnKey: ["_field"], rowKey: ["_time"], valueColumn: "_value")
195200
|> yield(name: "last")
196-
`, f.start.Format(time.RFC3339), f.end.Format(time.RFC3339), name, unit, f.goBranch, f.goos, f.goarch, f.repository)
201+
`, f.start.Format(time.RFC3339), f.end.Format(time.RFC3339), name, unit, f.goBranch, f.goos, f.goos, f.goos, f.goarch, f.goarch, f.goarch, f.repository)
197202

198203
res, err := influxQuery(ctx, qc, query)
199204
if err != nil {
@@ -224,31 +229,18 @@ func fetchDefaultBenchmarks(ctx context.Context, qc api.QueryAPI, f *filter) ([]
224229
// Keep benchmarks with the same name grouped together, which is
225230
// assumed by the JS.
226231
benchmarks := []struct{ name, unit string }{
227-
{"Tile38QueryLoad-16", "sec/op"},
228-
{"Tile38QueryLoad-16", "p50-latency-sec"},
229-
{"Tile38QueryLoad-16", "p90-latency-sec"},
230-
{"Tile38QueryLoad-16", "p99-latency-sec"},
231-
{"Tile38QueryLoad-16", "average-RSS-bytes"},
232-
{"Tile38QueryLoad-16", "peak-RSS-bytes"},
233-
{"Tile38QueryLoad-88", "sec/op"},
234-
{"Tile38QueryLoad-88", "p50-latency-sec"},
235-
{"Tile38QueryLoad-88", "p90-latency-sec"},
236-
{"Tile38QueryLoad-88", "p99-latency-sec"},
237-
{"Tile38QueryLoad-88", "average-RSS-bytes"},
238-
{"Tile38QueryLoad-88", "peak-RSS-bytes"},
239-
{"EtcdPut-16", "sec/op"},
240-
{"EtcdPut-16", "p50-latency-sec"},
241-
{"EtcdPut-16", "p90-latency-sec"},
242-
{"EtcdPut-16", "p99-latency-sec"},
243-
{"EtcdPut-16", "average-RSS-bytes"},
244-
{"EtcdPut-16", "peak-RSS-bytes"},
245-
{"GoBuildKubelet-16", "sec/op"},
246-
{"GoBuildKubeletLink-16", "sec/op"},
247-
{"GoBuildKubelet-88", "sec/op"},
248-
{"GoBuildKubeletLink-88", "sec/op"},
249-
{"RegexMatch-16", "sec/op"},
250-
{"BuildJSON-16", "sec/op"},
251-
{"ZapJSON-16", "sec/op"},
232+
{"geomean/go/vs_release/c2s16", "sec/op"},
233+
{"geomean/go/vs_release/c2s16", "average-RSS-bytes"},
234+
{"geomean/go/vs_release/c2s16", "peak-RSS-bytes"},
235+
{"geomean/go/vs_release/c4as16", "sec/op"},
236+
{"geomean/go/vs_release/c4as16", "average-RSS-bytes"},
237+
{"geomean/go/vs_release/c4as16", "peak-RSS-bytes"},
238+
{"geomean/go/vs_release/c3h88", "sec/op"},
239+
{"geomean/go/vs_release/c3h88", "average-RSS-bytes"},
240+
{"geomean/go/vs_release/c3h88", "peak-RSS-bytes"},
241+
{"geomean/go/vs_release/c4ah72", "sec/op"},
242+
{"geomean/go/vs_release/c4ah72", "average-RSS-bytes"},
243+
{"geomean/go/vs_release/c4ah72", "peak-RSS-bytes"},
252244
}
253245

254246
ret := make([]*BenchmarkJSON, 0, len(benchmarks))
@@ -272,11 +264,15 @@ func fetchNamedBenchmark(ctx context.Context, qc api.QueryAPI, f *filter, name s
272264
if err := validateFluxString(f.repository); err != nil {
273265
return nil, fmt.Errorf("invalid repository name: %w", err)
274266
}
275-
if err := validateFluxString(f.goos); err != nil {
276-
return nil, fmt.Errorf("invalid GOOS: %w", err)
267+
if f.goos != "" {
268+
if err := validateFluxString(f.goos); err != nil {
269+
return nil, fmt.Errorf("invalid GOOS: %w", err)
270+
}
277271
}
278-
if err := validateFluxString(f.goarch); err != nil {
279-
return nil, fmt.Errorf("invalid GOOS: %w", err)
272+
if f.goarch != "" {
273+
if err := validateFluxString(f.goarch); err != nil {
274+
return nil, fmt.Errorf("invalid GOOS: %w", err)
275+
}
280276
}
281277
if err := validateFluxString(f.goBranch); err != nil {
282278
return nil, fmt.Errorf("invalid go branch name: %w", err)
@@ -294,13 +290,13 @@ from(bucket: "perf")
294290
|> filter(fn: (r) => r["_measurement"] == "benchmark-result")
295291
|> filter(fn: (r) => r["name"] == "%s")
296292
|> filter(fn: (r) => r["branch"] == "%s")
297-
|> filter(fn: (r) => r["goos"] == "%s")
298-
|> filter(fn: (r) => r["goarch"] == "%s")
293+
|> filter(fn: (r) => ("%s" != "" and r["goos"] == "%s") or "%s" == "")
294+
|> filter(fn: (r) => ("%s" != "" and r["goarch"] == "%s") or "%s" == "")
299295
|> fill(column: "repository", value: "go")
300296
|> filter(fn: (r) => r["repository"] == "%s")
301297
|> pivot(columnKey: ["_field"], rowKey: ["_time"], valueColumn: "_value")
302298
|> yield(name: "last")
303-
`, f.start.Format(time.RFC3339), f.end.Format(time.RFC3339), name, f.goBranch, f.goos, f.goarch, f.repository)
299+
`, f.start.Format(time.RFC3339), f.end.Format(time.RFC3339), name, f.goBranch, f.goos, f.goos, f.goos, f.goarch, f.goarch, f.goarch, f.repository)
304300

305301
res, err := influxQuery(ctx, qc, query)
306302
if err != nil {
@@ -322,11 +318,15 @@ func fetchAllBenchmarks(ctx context.Context, qc api.QueryAPI, regressions bool,
322318
if err := validateFluxString(f.repository); err != nil {
323319
return nil, fmt.Errorf("invalid repository name: %w", err)
324320
}
325-
if err := validateFluxString(f.goos); err != nil {
326-
return nil, fmt.Errorf("invalid GOOS: %w", err)
321+
if f.goos != "" {
322+
if err := validateFluxString(f.goos); err != nil {
323+
return nil, fmt.Errorf("invalid GOOS: %w", err)
324+
}
327325
}
328-
if err := validateFluxString(f.goarch); err != nil {
329-
return nil, fmt.Errorf("invalid GOOS: %w", err)
326+
if f.goarch != "" {
327+
if err := validateFluxString(f.goarch); err != nil {
328+
return nil, fmt.Errorf("invalid GOOS: %w", err)
329+
}
330330
}
331331
if err := validateFluxString(f.goBranch); err != nil {
332332
return nil, fmt.Errorf("invalid go branch name: %w", err)
@@ -340,13 +340,13 @@ from(bucket: "perf")
340340
|> range(start: %s, stop: %s)
341341
|> filter(fn: (r) => r["_measurement"] == "benchmark-result")
342342
|> filter(fn: (r) => r["branch"] == "%s")
343-
|> filter(fn: (r) => r["goos"] == "%s")
344-
|> filter(fn: (r) => r["goarch"] == "%s")
343+
|> filter(fn: (r) => ("%s" != "" and r["goos"] == "%s") or "%s" == "")
344+
|> filter(fn: (r) => ("%s" != "" and r["goarch"] == "%s") or "%s" == "")
345345
|> fill(column: "repository", value: "go")
346346
|> filter(fn: (r) => r["repository"] == "%s")
347347
|> pivot(columnKey: ["_field"], rowKey: ["_time"], valueColumn: "_value")
348348
|> yield(name: "last")
349-
`, f.start.Format(time.RFC3339), f.end.Format(time.RFC3339), f.goBranch, f.goos, f.goarch, f.repository)
349+
`, f.start.Format(time.RFC3339), f.end.Format(time.RFC3339), f.goBranch, f.goos, f.goos, f.goos, f.goarch, f.goarch, f.goarch, f.repository)
350350

351351
res, err := influxQuery(ctx, qc, query)
352352
if err != nil {
@@ -371,8 +371,10 @@ type RegressionJSON struct {
371371
// results are sorted into commit-date order.
372372
func queryToJson(res *api.QueryTableResult) ([]*BenchmarkJSON, error) {
373373
type key struct {
374-
name string
375-
unit string
374+
name string
375+
unit string
376+
goos string
377+
goarch string
376378
}
377379

378380
m := make(map[key]*BenchmarkJSON)
@@ -390,12 +392,23 @@ func queryToJson(res *api.QueryTableResult) ([]*BenchmarkJSON, error) {
390392
return nil, fmt.Errorf("record %s unit value got type %T want string", rec, rec.ValueByKey("unit"))
391393
}
392394

393-
k := key{name, unit}
395+
goos, ok := rec.ValueByKey("goos").(string)
396+
if !ok {
397+
return nil, fmt.Errorf("record %s goos value got type %T want string", rec, rec.ValueByKey("goos"))
398+
}
399+
400+
goarch, ok := rec.ValueByKey("goarch").(string)
401+
if !ok {
402+
return nil, fmt.Errorf("record %s goarch value got type %T want string", rec, rec.ValueByKey("goarch"))
403+
}
404+
405+
k := key{name, unit, goos, goarch}
394406
b, ok := m[k]
395407
if !ok {
396408
b = &BenchmarkJSON{
397409
Name: name,
398410
Unit: unit,
411+
Platform: goos + "/" + goarch,
399412
HigherIsBetter: isHigherBetter(unit),
400413
}
401414
m[k] = b
@@ -466,10 +479,13 @@ func groupBenchmarkResults(res *api.QueryTableResult, byRegression bool) ([]*Ben
466479
// Keep benchmarks with the same name grouped together, which is
467480
// assumed by the JS.
468481
sort.Slice(s, func(i, j int) bool {
469-
if s[i].Name == s[j].Name {
470-
return s[i].Unit < s[j].Unit
482+
if s[i].Name != s[j].Name {
483+
return s[i].Name < s[j].Name
471484
}
472-
return s[i].Name < s[j].Name
485+
if s[i].Platform != s[j].Platform {
486+
return s[i].Platform < s[j].Platform
487+
}
488+
return s[i].Unit < s[j].Unit
473489
})
474490
return s, nil
475491
}
@@ -668,23 +684,25 @@ func (a *App) dashboardData(w http.ResponseWriter, r *http.Request) {
668684
}
669685
branch = latestRelease(releases).BranchName
670686
}
671-
platform := r.FormValue("platform")
672-
if platform == "" {
673-
platform = "linux/amd64"
674-
}
675-
goos, goarch, err := parsePlatform(platform)
676-
if err != nil {
677-
log.Printf("Invalid platform %q: %v", platform, err)
678-
http.Error(w, "Error parsing platform", 500)
679-
}
680687
f := &filter{
681688
start: start,
682689
end: end,
683690
repository: repository,
684-
goos: goos,
685-
goarch: goarch,
686691
goBranch: branch,
687692
}
693+
platform := r.FormValue("platform")
694+
if platform == "" {
695+
platform = "all"
696+
}
697+
if platform != "all" {
698+
goos, goarch, err := parsePlatform(platform)
699+
if err != nil {
700+
log.Printf("Invalid platform %q: %v", platform, err)
701+
http.Error(w, "Error parsing platform", 400)
702+
}
703+
f.goos = goos
704+
f.goarch = goarch
705+
}
688706

689707
historyBranch := branch
690708
if repository != "go" {

0 commit comments

Comments
 (0)