From 05ca34093bc2d4a367743101ac2a17b697809e75 Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Wed, 2 May 2018 09:45:40 +0200 Subject: [PATCH] testing: only compute b.N once when passed -count > 1 When running a benchmark multiple times, instead of re-computing the value of b.N each time, use the value found by the first run. For go test -bench=. -benchtime 3s -count 2 p_test.go on the benchmark in the linked issue; before: BenchmarkBenchmark-4 500 10180593 ns/op --- BENCH: BenchmarkBenchmark-4 p_test.go:13: single call took 10.111079ms p_test.go:13: single call took 1.017298685s p_test.go:13: single call took 5.090096124s BenchmarkBenchmark-4 500 10182164 ns/op --- BENCH: BenchmarkBenchmark-4 p_test.go:13: single call took 10.098169ms p_test.go:13: single call took 1.017712905s p_test.go:13: single call took 5.090898517s PASS ok command-line-arguments 12.244s and after: BenchmarkBenchmark-4 500 10177076 ns/op --- BENCH: BenchmarkBenchmark-4 p_test.go:13: single call took 10.091301ms p_test.go:13: single call took 1.016943125s p_test.go:13: single call took 5.088376028s BenchmarkBenchmark-4 500 10171497 ns/op --- BENCH: BenchmarkBenchmark-4 p_test.go:13: single call took 10.140245ms p_test.go:13: single call took 5.085605921s PASS ok command-line-arguments 11.218s Fixes #23423 Change-Id: Ie66a8c5ac43881eb8741e14105db28745b4d56d3 Reviewed-on: https://go-review.googlesource.com/110775 Reviewed-by: Brad Fitzpatrick --- src/cmd/go/go_test.go | 4 ---- src/testing/benchmark.go | 47 +++++++++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index b9737688fe..4b68c40382 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -4911,10 +4911,6 @@ func TestTestRegexps(t *testing.T) { x_test.go:15: LOG: Y running N=2000000000 --- BENCH: BenchmarkX/Y x_test.go:15: LOG: Y running N=1 - x_test.go:15: LOG: Y running N=100 - x_test.go:15: LOG: Y running N=10000 - x_test.go:15: LOG: Y running N=1000000 - x_test.go:15: LOG: Y running N=100000000 x_test.go:15: LOG: Y running N=2000000000 --- BENCH: BenchmarkX x_test.go:13: LOG: X running N=1 diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go index 4d569b7971..ac9ca58397 100644 --- a/src/testing/benchmark.go +++ b/src/testing/benchmark.go @@ -251,27 +251,20 @@ func (b *B) run() { b.context.processBench(b) // Must call doBench. } else { // Running func Benchmark. - b.doBench() + b.doBench(0) } } -func (b *B) doBench() BenchmarkResult { - go b.launch() +func (b *B) doBench(hint int) BenchmarkResult { + go b.launch(hint) <-b.signal return b.result } -// launch launches the benchmark function. It gradually increases the number -// of benchmark iterations until the benchmark runs for the requested benchtime. -// launch is run by the doBench function as a separate goroutine. -// run1 must have been called on b. -func (b *B) launch() { - // Signal that we're done whether we return normally - // or by FailNow's runtime.Goexit. - defer func() { - b.signal <- true - }() - +// autodetectN runs the benchmark function, gradually increasing the +// number of iterations until the benchmark runs for the requested +// benchtime. +func (b *B) autodetectN() { // Run the benchmark for at least the specified amount of time. d := b.benchTime for n := 1; !b.failed && b.duration < d && n < 1e9; { @@ -289,6 +282,26 @@ func (b *B) launch() { n = roundUp(n) b.runN(n) } +} + +// launch launches the benchmark function for hintN iterations. If +// hintN == 0, it autodetects the number of benchmark iterations based +// on the requested benchtime. +// launch is run by the doBench function as a separate goroutine. +// run1 must have been called on b. +func (b *B) launch(hintN int) { + // Signal that we're done whether we return normally + // or by FailNow's runtime.Goexit. + defer func() { + b.signal <- true + }() + + if hintN == 0 { + b.autodetectN() + } else { + b.runN(hintN) + } + b.result = BenchmarkResult{b.N, b.duration, b.bytes, b.netAllocs, b.netBytes} } @@ -426,6 +439,7 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e // processBench runs bench b for the configured CPU counts and prints the results. func (ctx *benchContext) processBench(b *B) { for i, procs := range cpuList { + var nHint int for j := uint(0); j < *count; j++ { runtime.GOMAXPROCS(procs) benchName := benchmarkName(b.name, procs) @@ -444,7 +458,10 @@ func (ctx *benchContext) processBench(b *B) { } b.run1() } - r := b.doBench() + r := b.doBench(nHint) + if j == 0 { + nHint = b.N + } if b.failed { // The output could be very long here, but probably isn't. // We print it all, regardless, because we don't want to trim the reason -- 2.50.0