On Tuesday, 24 March 2020 20:16:21 UTC, Jake Montgomery wrote:
>
> I took a quick glance at the code, and I think I figured it out. The 
> benchmark code, including StartTimer() and StopTimer() use time.Now(). On 
> my windows  machine time.Now() has an accuracy of 1ms. So by calling it for 
> every iteration, when the actual time is 600ns just makes the whole thing 
> wildly inaccurate. That 1ms accuracy is ok when the benchmark calls it once 
> then runs the code 2 million times. But when called each time the accuracy 
> of the time.Now() code becomes dominant. 
>
> It is just an educated guess, but that is what it looks like to me.
>

Thanks once again. Others on the thread have pointed out more potential 
issues. I feel a bit like a carpenter who has to measure a piece of wood 
but who only has a rubber rule :D

 

>
>
> Perhaps there should be some sort of warning in the docs? 
>
>
>
> On Tuesday, March 24, 2020 at 4:01:17 PM UTC-4, Orson Cart wrote:
>>
>> On Tuesday, 24 March 2020 19:51:24 UTC, Jake Montgomery wrote:
>>>
>>> Strange. I hope someone has a real answer for you.
>>>
>>> In the meantime, you can simplify your example to demonstrate the issue:
>>>
>>
>> Thanks for taking a look at the code Jake. Just one question: you have 
>> the call to b.StopTimer outside of the loop and the call to b.StartTimer 
>> inside. Was that intentional?
>>
>> I'd have thought that the call to b.StartTimer would be a no-op after the 
>> first iteration.
>>
>>
>>
>>
>>
>>
>>  
>>
>>>
>>> package demo_test
>>>
>>> import (
>>>     "testing"
>>> )
>>>
>>> var Foo1 []string
>>> var Count int = 8
>>>
>>> func Benchmark1(b *testing.B) {
>>>     for i := 0; i < b.N; i++ {
>>>         Foo1 = foo(Count)
>>>     }
>>> }
>>>
>>> func Benchmark2(b *testing.B) {
>>>     b.StopTimer()
>>>     for i := 0; i < b.N; i++ {
>>>         // Hypothetical setup here 
>>>         b.StartTimer()
>>>         Foo1 = foo(Count)
>>>         b.StopTimer()
>>>     }
>>> }
>>>
>>>
>>> func foo(count int) []string {
>>>     testData := []string{}
>>>     for i := 0; i < count; i++ {
>>>         testData = append(testData, "a")
>>>     }
>>>
>>>     return testData
>>> }
>>>
>>> I get:
>>>
>>> goos: windows
>>> goarch: amd64
>>> Benchmark1-4     2101567               584 ns/op
>>> Benchmark2-4     1000000              1668 ns/op
>>> PASS
>>>
>>> So it appears that StopTimer() and StartTimer() are introducing some 
>>> overhead. I am surprised that it is this large.
>>>
>>> Good Luck
>>>
>>>
>>>
>>> On Tuesday, March 24, 2020 at 12:24:08 PM UTC-4, Orson Cart wrote:
>>>>
>>>> I posted this earlier but I realised that the code had a fundamental 
>>>> error in it. I've corrected here it but the underlying problem still 
>>>> exists.
>>>>
>>>> I've recently started using go test's benchmarks support and I'm 
>>>> particularly interested in understanding the benchmark timer functions. 
>>>> I've been getting results that I found surprising and I was wondering if 
>>>> anyone could explain what's going on here.
>>>>
>>>> The code below has three benchmarks that each invoke a single function 
>>>> (foo). The implementation of foo isn't important, it's just there to 
>>>> consume some time:
>>>> - foo is called once per iteration in Benchmark1.
>>>> - It's called twice per iteration in Benchmark2 so I'd expect 
>>>> Benchmark2's duration to be nominally twice that of Benchmark1.
>>>> - It's also called twice per iteration in Benchmark3 but the first call 
>>>> is wrapped in b.StopTimer and b.startTimer calls. Because of this I'd have 
>>>> expected Benchmark3 to be about the same duration as Benchmark1
>>>>
>>>> Apologies for the length of the example but I didn't think it fair to 
>>>> ask the question and leave anything out.
>>>>
>>>> package demo_test
>>>>
>>>> import (
>>>> "strconv"
>>>> "testing"
>>>> )
>>>>
>>>> var Foo1 []string
>>>> var Foo2 []string
>>>> var Count int = 32767
>>>>
>>>> func Benchmark1(b *testing.B) {
>>>> for i := 0; i < b.N; i++{
>>>> Foo1 = foo(Count)
>>>> }
>>>> }
>>>>
>>>> func Benchmark2(b *testing.B) {
>>>> for i := 0; i < b.N; i++{
>>>> Foo1 = foo(Count)
>>>> Foo2 = foo(Count)
>>>> }
>>>> }
>>>>
>>>> func Benchmark3(b *testing.B) {
>>>> for i := 0; i < b.N; i++{
>>>> b.StopTimer()
>>>> Foo1 = foo(Count)
>>>> b.StartTimer()
>>>> Foo2 = foo(Count)
>>>> }
>>>> }
>>>>
>>>> func foo(count int) []string{
>>>> testData := []string{}
>>>> for i:= 0; i < count; i++ {
>>>> testData = append(testData, strconv.Itoa(i))
>>>> }
>>>>
>>>> return testData
>>>> }
>>>>
>>>>
>>>> When the benchmarks are run the results are as follows:
>>>>
>>>> Benchmark1-4         351           3345215 ns/op
>>>> Benchmark2-4         166           7206582 ns/op
>>>> Benchmark3-4         334           3457907 ns/op
>>>> PASS
>>>> ok      bar.com/benchmarks      6.881s
>>>>
>>>> OK benchmark3 is a little slower than Benchmark1 but that's not what's 
>>>> bothering me. It's this: if I now change Count to something much smaller 
>>>> the results are a surprise, at least to me. Here are the results when 
>>>> Count 
>>>> = 8:
>>>>
>>>> Benchmark1-4     2706196               442 ns/op
>>>> Benchmark2-4     1357482               873 ns/op
>>>> Benchmark3-4      840729              1387 ns/op
>>>> PASS
>>>> ok      bar.com/benchmarks      23.547s
>>>>
>>>> The ratio of timings for Benchmark1 and Benchmark2 are roughly in line 
>>>> with expectations but I was surprised to see that the timings for 
>>>> Benchmark3 are now larger than those for Benchmark2.
>>>>
>>>> Can anyone explain this?
>>>>
>>>> TIA
>>>> Orson
>>>>
>>>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/0f718800-042a-4176-b4dd-545e86e0b655%40googlegroups.com.

Reply via email to