Skip to content

Commit 05ca340

Browse files
committed
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 golang#23423 Change-Id: Ie66a8c5ac43881eb8741e14105db28745b4d56d3 Reviewed-on: https://go-review.googlesource.com/110775 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
1 parent 3c8545c commit 05ca340

File tree

2 files changed

+32
-19
lines changed

2 files changed

+32
-19
lines changed

src/cmd/go/go_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4911,10 +4911,6 @@ func TestTestRegexps(t *testing.T) {
49114911
x_test.go:15: LOG: Y running N=2000000000
49124912
--- BENCH: BenchmarkX/Y
49134913
x_test.go:15: LOG: Y running N=1
4914-
x_test.go:15: LOG: Y running N=100
4915-
x_test.go:15: LOG: Y running N=10000
4916-
x_test.go:15: LOG: Y running N=1000000
4917-
x_test.go:15: LOG: Y running N=100000000
49184914
x_test.go:15: LOG: Y running N=2000000000
49194915
--- BENCH: BenchmarkX
49204916
x_test.go:13: LOG: X running N=1

src/testing/benchmark.go

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -251,27 +251,20 @@ func (b *B) run() {
251251
b.context.processBench(b) // Must call doBench.
252252
} else {
253253
// Running func Benchmark.
254-
b.doBench()
254+
b.doBench(0)
255255
}
256256
}
257257

258-
func (b *B) doBench() BenchmarkResult {
259-
go b.launch()
258+
func (b *B) doBench(hint int) BenchmarkResult {
259+
go b.launch(hint)
260260
<-b.signal
261261
return b.result
262262
}
263263

264-
// launch launches the benchmark function. It gradually increases the number
265-
// of benchmark iterations until the benchmark runs for the requested benchtime.
266-
// launch is run by the doBench function as a separate goroutine.
267-
// run1 must have been called on b.
268-
func (b *B) launch() {
269-
// Signal that we're done whether we return normally
270-
// or by FailNow's runtime.Goexit.
271-
defer func() {
272-
b.signal <- true
273-
}()
274-
264+
// autodetectN runs the benchmark function, gradually increasing the
265+
// number of iterations until the benchmark runs for the requested
266+
// benchtime.
267+
func (b *B) autodetectN() {
275268
// Run the benchmark for at least the specified amount of time.
276269
d := b.benchTime
277270
for n := 1; !b.failed && b.duration < d && n < 1e9; {
@@ -289,6 +282,26 @@ func (b *B) launch() {
289282
n = roundUp(n)
290283
b.runN(n)
291284
}
285+
}
286+
287+
// launch launches the benchmark function for hintN iterations. If
288+
// hintN == 0, it autodetects the number of benchmark iterations based
289+
// on the requested benchtime.
290+
// launch is run by the doBench function as a separate goroutine.
291+
// run1 must have been called on b.
292+
func (b *B) launch(hintN int) {
293+
// Signal that we're done whether we return normally
294+
// or by FailNow's runtime.Goexit.
295+
defer func() {
296+
b.signal <- true
297+
}()
298+
299+
if hintN == 0 {
300+
b.autodetectN()
301+
} else {
302+
b.runN(hintN)
303+
}
304+
292305
b.result = BenchmarkResult{b.N, b.duration, b.bytes, b.netAllocs, b.netBytes}
293306
}
294307

@@ -426,6 +439,7 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e
426439
// processBench runs bench b for the configured CPU counts and prints the results.
427440
func (ctx *benchContext) processBench(b *B) {
428441
for i, procs := range cpuList {
442+
var nHint int
429443
for j := uint(0); j < *count; j++ {
430444
runtime.GOMAXPROCS(procs)
431445
benchName := benchmarkName(b.name, procs)
@@ -444,7 +458,10 @@ func (ctx *benchContext) processBench(b *B) {
444458
}
445459
b.run1()
446460
}
447-
r := b.doBench()
461+
r := b.doBench(nHint)
462+
if j == 0 {
463+
nHint = b.N
464+
}
448465
if b.failed {
449466
// The output could be very long here, but probably isn't.
450467
// We print it all, regardless, because we don't want to trim the reason

0 commit comments

Comments
 (0)