I've run into a problem benchmarking my Go programs, and it looks to me like a Go bug. Please help me understand why it's not.
In a nutshell: benchmarking hangs when I call b.StopTimer()
even if I then call b.StartTimer()
afterwards. AFAICT I am using the functions as intended.
This is on Mac OSX 10.11.5 "El Capitan," with go version go1.6.1 darwin/amd64
; everything else seems to be fine. I will try to check this on Linux later today and update the question.
Here's the code. Run with go test -bench=.
as usual.
package bmtimer
import (
"testing"
"time"
)
// These appear to not matter; they can be very short.
var COSTLY_PREP_DELAY = time.Nanosecond
var RESET_STATE_DELAY = time.Nanosecond
// This however -- the measured function delay -- must not be too short.
// The shorter it is, the more iterations will be timed. If it's infinitely
// short then you will hang -- or perhaps *appear* to hang?
var FUNCTION_OF_INTEREST_DELAY = time.Microsecond
func CostlyPrep() { time.Sleep(COSTLY_PREP_DELAY) }
func ResetState() { time.Sleep(RESET_STATE_DELAY) }
func FunctionOfInterest() { time.Sleep(FUNCTION_OF_INTEREST_DELAY) }
func TestPlaceHolder(t *testing.T) {}
func BenchmarkSomething(b *testing.B) {
CostlyPrep()
b.ResetTimer()
for n := 0; n < b.N; n++ {
FunctionOfInterest()
b.StopTimer()
ResetState()
b.StartTimer()
}
}
Thanks in advance for any tips! I've come up short on Google as well as here.
Edit: It seems this only happens of FunctionOfInterest()
is really fast; and yes, I specifically want to do this inside my benchmark loop. I've updated the sample code to make that more clear. And I think I have it figured out now.
CostlyPrep()
instead ofFunctionOfInterest()
then suddenly it works. – GaugerStopTimer
blocks on a call toruntime.ReadMemStats
, which requires astopTheWorld
call. You basically shouldn't be stopping and starting the timer in the benchmark loop. – Softenb.ResetTimer()
for any prep that happens before the benchmark loop. I get that it's not optimal but -- also to @user114241 on this -- there absolutely are cases where you have to fiddle with state in the benchmark loop in order for the benchmark to be meaningful. You then need to factor out the time spent fiddling, one way or another. – Gaugerbenchtime
flag rather than setting the desired benchmark duration (or relying on the default one of1s
): for instance, use-benchtime=100x
. – Exoskeleton