如果我需要在每次迭代中重置,如何进行基准测试?

How to benchmark if I need a reset in each iteration?

我使用回溯编写了一个小型数独求解器。现在我想对这个函数的速度进行基准测试。这是我当前的代码:

type Board struct {
    Cells [9][9]int
}

func BenchmarkBacktrack(b *testing.B) {
    for i := 0; i < b.N; i++ {
        b.StopTimer()
        // prevent the modification of the orignal board
        copy := &Board{
            Cells: exampleBoard.Cells,
        }
        b.StartTimer()
        copy.Backtrack()
     }
}

因为 &Board 是指针,所以我会在第一次迭代中解决数独问题,在下一次迭代中我会回溯已解决的板。因此,我在每次迭代开始时重置电路板。 exampleBoard 填充了示例值。

他们是否是一种更好的方法来对功能进行基准测试,而无需一遍又一遍地停止和重新启动计时器?

函数调用不会花费少量时间来影响基准测试吗?

您可以尝试提供一个 func NewBoard([9][9]int) *Board 方法,它只从示例数据初始化一个板。然后在新板上为 Backtrack() 写一个基准,为 NewBoard().

写一个单独的基准

将这两个数字相减应该可以让您大致了解回溯方法的速度。

type Board struct {
    Cells [9][9]int
}

var scratch *Board

func NewBoard(cells [9][9]int) *Board {
    return &Board{Cells: cells}
}

func BenchmarkBacktrack(b *testing.B) {
    for i := 0; i < b.N; i++ {
        scratch = NewBoard(exampleBoard.Cells)
        scratch.Backtrack()
}

func BenchmarkNewBoard(b *testing.B) {
    for i := 0; i < b.N; i++ {
        scratch = NewBoard(exampleBoard.Cells)
}

还要注意 scratch 变量的使用。尝试在基准循环内创建循环局部变量可能会导致编译器根据 presence/absence 的副作用优化对 NewBoard() 的调用。对于奇偶校验,您需要在两个基准测试中使用 scratch 变量。

And wouldn't cost the function calls a small amount of time that that impacts the benchmark?

当然会。 for 循环也是如此,它包含在基准测试中。加上调用 copy.Backtrack 函数的开销。但问题是,这应该是无关紧要的,除非您对单个操作进行基准测试需要纳秒(在这种情况下您不应该这样做)。创建一个空板可能是一个微不足道的操作,所以我根本不会碰定时器。如果它不是微不足道的,那么你做对了——调用 StopTimer。这正是发明它的原因:

StopTimer stops timing a test. This can be used to pause the timer while performing complex initialization that you don't want to measure.