@@ -176,10 +176,6 @@ func (b *B) ReportAllocs() {
176
176
177
177
// runN runs a single benchmark for the specified number of iterations.
178
178
func (b * B ) runN (n int ) {
179
- if b .done {
180
- panic ("testing: internal error: runN when benchmark is already done" )
181
- }
182
-
183
179
benchmarkLock .Lock ()
184
180
defer benchmarkLock .Unlock ()
185
181
defer func () {
@@ -200,46 +196,46 @@ func (b *B) runN(n int) {
200
196
b .previousDuration = b .duration
201
197
}
202
198
203
- // run1 runs the first iteration of benchFunc.
204
- //
205
- // If no more iterations of this benchmark should be done, run1 sets b.done.
206
- func (b * B ) run1 () {
199
+ // run1 runs the first iteration of benchFunc. It reports whether more
200
+ // iterations of this benchmarks should be run.
201
+ func (b * B ) run1 () bool {
207
202
if ctx := b .context ; ctx != nil {
208
203
// Extend maxLen, if needed.
209
204
if n := len (b .name ) + ctx .extLen + 1 ; n > ctx .maxLen {
210
205
ctx .maxLen = n + 8 // Add additional slack to avoid too many jumps in size.
211
206
}
212
207
}
213
-
214
- runOneDone := make (chan struct {})
215
208
go func () {
216
209
// Signal that we're done whether we return normally
217
210
// or by FailNow's runtime.Goexit.
218
- defer close (runOneDone )
211
+ defer func () {
212
+ b .signal <- true
213
+ }()
214
+
219
215
b .runN (1 )
220
216
}()
221
- <- runOneDone
222
-
217
+ <- b .signal
223
218
if b .failed {
224
219
fmt .Fprintf (b .w , "%s--- FAIL: %s\n %s" , b .chatty .prefix (), b .name , b .output )
225
- b .done = true
226
- close (b .doneOrParallel )
227
- return
220
+ return false
228
221
}
229
222
// Only print the output if we know we are not going to proceed.
230
223
// Otherwise it is printed in processBench.
231
- if b .hasSub .Load () || b .skipped {
224
+ b .mu .RLock ()
225
+ finished := b .finished
226
+ b .mu .RUnlock ()
227
+ if b .hasSub .Load () || finished {
232
228
tag := "BENCH"
233
229
if b .skipped {
234
230
tag = "SKIP"
235
231
}
236
- if b .chatty != nil && (len (b .output ) > 0 || b . skipped ) {
232
+ if b .chatty != nil && (len (b .output ) > 0 || finished ) {
237
233
b .trimOutput ()
238
234
fmt .Fprintf (b .w , "%s--- %s: %s\n %s" , b .chatty .prefix (), tag , b .name , b .output )
239
235
}
240
- b .done = true
241
- close (b .doneOrParallel )
236
+ return false
242
237
}
238
+ return true
243
239
}
244
240
245
241
var labelsOnce sync.Once
@@ -266,10 +262,9 @@ func (b *B) run() {
266
262
}
267
263
}
268
264
269
- // doBench calls b.launch in a separate goroutine and waits for it to complete.
270
265
func (b * B ) doBench () BenchmarkResult {
271
266
go b .launch ()
272
- <- b .doneOrParallel
267
+ <- b .signal
273
268
return b .result
274
269
}
275
270
@@ -281,10 +276,7 @@ func (b *B) launch() {
281
276
// Signal that we're done whether we return normally
282
277
// or by FailNow's runtime.Goexit.
283
278
defer func () {
284
- b .result = BenchmarkResult {b .N , b .duration , b .bytes , b .netAllocs , b .netBytes , b .extra }
285
- b .setRanLeaf ()
286
- b .done = true
287
- close (b .doneOrParallel )
279
+ b .signal <- true
288
280
}()
289
281
290
282
// Run the benchmark for at least the specified amount of time.
@@ -324,6 +316,7 @@ func (b *B) launch() {
324
316
b .runN (int (n ))
325
317
}
326
318
}
319
+ b .result = BenchmarkResult {b .N , b .duration , b .bytes , b .netAllocs , b .netBytes , b .extra }
327
320
}
328
321
329
322
// Elapsed returns the measured elapsed time of the benchmark.
@@ -557,7 +550,6 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e
557
550
main .chatty = newChattyPrinter (main .w )
558
551
}
559
552
main .runN (1 )
560
- main .done = true
561
553
return ! main .failed
562
554
}
563
555
@@ -576,21 +568,18 @@ func (ctx *benchContext) processBench(b *B) {
576
568
if i > 0 || j > 0 {
577
569
b = & B {
578
570
common : common {
579
- doneOrParallel : make (chan struct {} ),
580
- name : b .name ,
581
- w : b .w ,
582
- chatty : b .chatty ,
583
- bench : true ,
571
+ signal : make (chan bool ),
572
+ name : b .name ,
573
+ w : b .w ,
574
+ chatty : b .chatty ,
575
+ bench : true ,
584
576
},
585
577
benchFunc : b .benchFunc ,
586
578
benchTime : b .benchTime ,
587
579
}
588
580
b .run1 ()
589
581
}
590
- var r BenchmarkResult
591
- if ! b .done {
592
- r = b .doBench ()
593
- }
582
+ r := b .doBench ()
594
583
if b .failed {
595
584
// The output could be very long here, but probably isn't.
596
585
// We print it all, regardless, because we don't want to trim the reason
@@ -633,13 +622,6 @@ var hideStdoutForTesting = false
633
622
// A subbenchmark is like any other benchmark. A benchmark that calls Run at
634
623
// least once will not be measured itself and will be called once with N=1.
635
624
func (b * B ) Run (name string , f func (b * B )) bool {
636
- if b .previousN > 0 {
637
- // If the benchmark calls Run we will only call it once with N=1.
638
- // If it doesn't call Run the first time we try it, it must not
639
- // call run on subsequent invocations either.
640
- panic ("testing: unexpected call to B.Run during iteration" )
641
- }
642
-
643
625
// Since b has subbenchmarks, we will no longer run it as a benchmark itself.
644
626
// Release the lock and acquire it on exit to ensure locks stay paired.
645
627
b .hasSub .Store (true )
@@ -657,14 +639,14 @@ func (b *B) Run(name string, f func(b *B)) bool {
657
639
n := runtime .Callers (2 , pc [:])
658
640
sub := & B {
659
641
common : common {
660
- doneOrParallel : make (chan struct {} ),
661
- name : benchName ,
662
- parent : & b .common ,
663
- level : b .level + 1 ,
664
- creator : pc [:n ],
665
- w : b .w ,
666
- chatty : b .chatty ,
667
- bench : true ,
642
+ signal : make (chan bool ),
643
+ name : benchName ,
644
+ parent : & b .common ,
645
+ level : b .level + 1 ,
646
+ creator : pc [:n ],
647
+ w : b .w ,
648
+ chatty : b .chatty ,
649
+ bench : true ,
668
650
},
669
651
importPath : b .importPath ,
670
652
benchFunc : f ,
@@ -697,8 +679,7 @@ func (b *B) Run(name string, f func(b *B)) bool {
697
679
}
698
680
}
699
681
700
- sub .run1 ()
701
- if ! sub .done {
682
+ if sub .run1 () {
702
683
sub .run ()
703
684
}
704
685
b .add (sub .result )
@@ -842,14 +823,13 @@ func (b *B) SetParallelism(p int) {
842
823
func Benchmark (f func (b * B )) BenchmarkResult {
843
824
b := & B {
844
825
common : common {
845
- doneOrParallel : make (chan struct {} ),
846
- w : discard {},
826
+ signal : make (chan bool ),
827
+ w : discard {},
847
828
},
848
829
benchFunc : f ,
849
830
benchTime : benchTime ,
850
831
}
851
- b .run1 ()
852
- if ! b .done {
832
+ if b .run1 () {
853
833
b .run ()
854
834
}
855
835
return b .result
0 commit comments