【问题标题】:How to properly StartTime and StopTime in golang benchmark?如何在 golang 基准测试中正确地 StartTime 和 StopTime?
【发布时间】:2019-01-31 11:40:03
【问题描述】:

我写了一个benchmark来测试两个斐波那契数生成器的速度,源码是here on github

func BenchmarkFib(b *testing.B) {
    fibFuncs := []struct {
        name string
        f    func(int) int
    }{
        {"recursive", fibRecu},
        {"iterative", fibIter},
    }
    for _, fibFunc := range fibFuncs {
        // calculate k'th Fibonacci number
        for k := 10; k < 1001; k *= 10 {
            b.Run(fmt.Sprintf("%s Fib %v", fibFunc.name, k), func(b *testing.B) {
                for n := 0; n < b.N; n++ {
                    //                  b.StopTimer()
                    // reset the memo
                    memo = map[int]int{0: 0, 1: 1, 2: 1}
                    //                  b.StartTimer()
                    fibFunc.f(k)
                }
            })
        }
    }
}

事实上,基准测试有效,输出为

nos (master) fibonacci $ go test -bench .
goos: linux
goarch: amd64
pkg: github.com/nosarthur/dynamicP/fibonacci
BenchmarkFib/recursive_Fib_10-4                  1000000              1256 ns/op
BenchmarkFib/recursive_Fib_100-4                  100000             18256 ns/op
BenchmarkFib/recursive_Fib_1000-4                  10000            206109 ns/op
BenchmarkFib/iterative_Fib_10-4                 10000000               218 ns/op
BenchmarkFib/iterative_Fib_100-4                 5000000               292 ns/op
BenchmarkFib/iterative_Fib_1000-4                2000000               881 ns/op
PASS
ok      github.com/nosarthur/dynamicP/fibonacci 12.208s

但是,我添加了b.StopTime()b.StartTime() 以排除重置备忘录的时间。这两行未注释,基准挂起,部分输出为

nos (master *) fibonacci $ go test -bench .
goos: linux
goarch: amd64
pkg: github.com/nosarthur/dynamicP/fibonacci
BenchmarkFib/recursive_Fib_10-4                  1000000              2139 ns/op
BenchmarkFib/recursive_Fib_100-4                  100000             24775 ns/op
BenchmarkFib/recursive_Fib_1000-4                   5000            239197 ns/op
BenchmarkFib/iterative_Fib_10-4                 ^Csignal: interrupt
FAIL    github.com/nosarthur/dynamicP/fibonacci 269.067s

排除备忘录重置的正确方法是什么?我的 go 版本是 1.10.1

【问题讨论】:

  • 您的代码不正确。你说The 93'th Fibonacci number is : -6246583658587674878.Overflow!
  • 不确定,但 b.Run 之外的 k 循环看起来很可疑。

标签: testing go benchmarking


【解决方案1】:

发生的情况是您的函数真的很快,尤其是在迭代函数和地图重置的情况下(以及 StartTimerStopTimer 函数本身与运行时stat 分配)要慢得多。

所以发生的情况是,当您调用 StopTimer 时,它会将基准的内部跟踪持续时间设置为仅运行函数所花费的时间。猜猜它如何估计在指定的基准时间内运行多少次迭代?是的,你猜对了 - 内部持续时间。

所以基本上,您的迭代函数运行大约需要 10ns,地图重置大约需要 250ns,而 Timer 函数需要更长的时间 - 但基准测试估计每次运行只需要 20ns 并相应地设置迭代次数。

我的建议 - 在这种情况下不要使用 StartTimer/StopTimer 函数,而只需在你的测试中添加第三次运行,这是一个非操作 - 基本上:

{"baseline", func(int) int {return 0}},

然后,只需从其他两组中减去该函数的时间,即可估算出分配与函数本身有多少 ns/op。

这是我运行此程序时的结果:

BenchmarkFib/baseline_Fib_10-2           5000000           357 ns/op
BenchmarkFib/baseline_Fib_100-2          5000000           327 ns/op
BenchmarkFib/baseline_Fib_1000-2         5000000           310 ns/op
BenchmarkFib/recursive_Fib_10-2          1000000          1659 ns/op
BenchmarkFib/recursive_Fib_100-2           50000         24898 ns/op
BenchmarkFib/recursive_Fib_1000-2           5000        301771 ns/op
BenchmarkFib/iterative_Fib_10-2          5000000           333 ns/op
BenchmarkFib/iterative_Fib_100-2         3000000           394 ns/op
BenchmarkFib/iterative_Fib_1000-2        1000000          1052 ns/op
PASS
ok      _/tmp/dynamicP/fibonacci    15.305s

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-08
    相关资源
    最近更新 更多