@@ -67,6 +67,7 @@ type DataJSON struct {
67
67
type BenchmarkJSON struct {
68
68
Name string
69
69
Unit string
70
+ Platform string
70
71
HigherIsBetter bool
71
72
72
73
// These will be sorted by CommitDate.
@@ -89,11 +90,11 @@ type ValueJSON struct {
89
90
90
91
// filter is a set of parameters used to filter influx data.
91
92
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.
97
98
}
98
99
99
100
func fluxRecordToValue (rec * query.FluxRecord ) (ValueJSON , error ) {
@@ -161,11 +162,15 @@ func fetchNamedUnitBenchmark(ctx context.Context, qc api.QueryAPI, f *filter, na
161
162
if err := validateFluxString (f .repository ); err != nil {
162
163
return nil , fmt .Errorf ("invalid repository name: %w" , err )
163
164
}
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
+ }
166
169
}
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
+ }
169
174
}
170
175
if err := validateFluxString (f .goBranch ); err != nil {
171
176
return nil , fmt .Errorf ("invalid go branch name: %w" , err )
@@ -187,13 +192,13 @@ from(bucket: "perf")
187
192
|> filter(fn: (r) => r["name"] == "%s")
188
193
|> filter(fn: (r) => r["unit"] == "%s")
189
194
|> 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" == " ")
192
197
|> fill(column: "repository", value: "go")
193
198
|> filter(fn: (r) => r["repository"] == "%s")
194
199
|> pivot(columnKey: ["_field"], rowKey: ["_time"], valueColumn: "_value")
195
200
|> 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 )
197
202
198
203
res , err := influxQuery (ctx , qc , query )
199
204
if err != nil {
@@ -224,31 +229,18 @@ func fetchDefaultBenchmarks(ctx context.Context, qc api.QueryAPI, f *filter) ([]
224
229
// Keep benchmarks with the same name grouped together, which is
225
230
// assumed by the JS.
226
231
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" },
252
244
}
253
245
254
246
ret := make ([]* BenchmarkJSON , 0 , len (benchmarks ))
@@ -272,11 +264,15 @@ func fetchNamedBenchmark(ctx context.Context, qc api.QueryAPI, f *filter, name s
272
264
if err := validateFluxString (f .repository ); err != nil {
273
265
return nil , fmt .Errorf ("invalid repository name: %w" , err )
274
266
}
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
+ }
277
271
}
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
+ }
280
276
}
281
277
if err := validateFluxString (f .goBranch ); err != nil {
282
278
return nil , fmt .Errorf ("invalid go branch name: %w" , err )
@@ -294,13 +290,13 @@ from(bucket: "perf")
294
290
|> filter(fn: (r) => r["_measurement"] == "benchmark-result")
295
291
|> filter(fn: (r) => r["name"] == "%s")
296
292
|> 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" == " ")
299
295
|> fill(column: "repository", value: "go")
300
296
|> filter(fn: (r) => r["repository"] == "%s")
301
297
|> pivot(columnKey: ["_field"], rowKey: ["_time"], valueColumn: "_value")
302
298
|> 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 )
304
300
305
301
res , err := influxQuery (ctx , qc , query )
306
302
if err != nil {
@@ -322,11 +318,15 @@ func fetchAllBenchmarks(ctx context.Context, qc api.QueryAPI, regressions bool,
322
318
if err := validateFluxString (f .repository ); err != nil {
323
319
return nil , fmt .Errorf ("invalid repository name: %w" , err )
324
320
}
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
+ }
327
325
}
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
+ }
330
330
}
331
331
if err := validateFluxString (f .goBranch ); err != nil {
332
332
return nil , fmt .Errorf ("invalid go branch name: %w" , err )
@@ -340,13 +340,13 @@ from(bucket: "perf")
340
340
|> range(start: %s, stop: %s)
341
341
|> filter(fn: (r) => r["_measurement"] == "benchmark-result")
342
342
|> 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" == " ")
345
345
|> fill(column: "repository", value: "go")
346
346
|> filter(fn: (r) => r["repository"] == "%s")
347
347
|> pivot(columnKey: ["_field"], rowKey: ["_time"], valueColumn: "_value")
348
348
|> 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 )
350
350
351
351
res , err := influxQuery (ctx , qc , query )
352
352
if err != nil {
@@ -371,8 +371,10 @@ type RegressionJSON struct {
371
371
// results are sorted into commit-date order.
372
372
func queryToJson (res * api.QueryTableResult ) ([]* BenchmarkJSON , error ) {
373
373
type key struct {
374
- name string
375
- unit string
374
+ name string
375
+ unit string
376
+ goos string
377
+ goarch string
376
378
}
377
379
378
380
m := make (map [key ]* BenchmarkJSON )
@@ -390,12 +392,23 @@ func queryToJson(res *api.QueryTableResult) ([]*BenchmarkJSON, error) {
390
392
return nil , fmt .Errorf ("record %s unit value got type %T want string" , rec , rec .ValueByKey ("unit" ))
391
393
}
392
394
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 }
394
406
b , ok := m [k ]
395
407
if ! ok {
396
408
b = & BenchmarkJSON {
397
409
Name : name ,
398
410
Unit : unit ,
411
+ Platform : goos + "/" + goarch ,
399
412
HigherIsBetter : isHigherBetter (unit ),
400
413
}
401
414
m [k ] = b
@@ -466,10 +479,13 @@ func groupBenchmarkResults(res *api.QueryTableResult, byRegression bool) ([]*Ben
466
479
// Keep benchmarks with the same name grouped together, which is
467
480
// assumed by the JS.
468
481
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
471
484
}
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
473
489
})
474
490
return s , nil
475
491
}
@@ -668,23 +684,25 @@ func (a *App) dashboardData(w http.ResponseWriter, r *http.Request) {
668
684
}
669
685
branch = latestRelease (releases ).BranchName
670
686
}
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
- }
680
687
f := & filter {
681
688
start : start ,
682
689
end : end ,
683
690
repository : repository ,
684
- goos : goos ,
685
- goarch : goarch ,
686
691
goBranch : branch ,
687
692
}
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
+ }
688
706
689
707
historyBranch := branch
690
708
if repository != "go" {
0 commit comments