gpt4 book ai didi

testing - 是否可以动态运行基准测试?

转载 作者:IT王子 更新时间:2023-10-29 01:19:05 25 4
gpt4 key购买 nike

我有几个不同的接口(interface)实现,以及我想测试它们的各种因素。最终目标是为不同情况下的不同实现制作结果网格。

我可以为每种可能的组合编写测试,但这会让人筋疲力尽:

func Benchmark_ImplA_N100_X300(b *testing.B){
impl := newImplA(100,300)
runBenchmark(b,impl)
}

我添加的组合越多,我就越需要复制/粘贴。这很快就会变得很麻烦。

我很想做这样的事情:

tests := []testing.InternalBenchmark{}
for _, n := range []int{50,100,500,10000}{
for _,x := range []int{300,200}{
for name, gen := range implementations{
impl = gen(n,x)
bm := testing.InternalBenchmark{Name: fmt.Sprint(name,x,n)}
bm.F = func(b *testing.B){
runBench(b,impl)
}
tests = append(tests,bm)
}
}
}
testing.RunBenchmarks(anything, tests)

这样我就可以更新组合列表,基准测试将神奇地在所有组合中运行。我在 main 和 TestMain 中尝试过类似的东西,但没有任何输出。我不确定是我用错了,还是测试包只是在做一些有趣的事情。

我真的不在乎 go test 工具是否可以处理它或者是否有其他方法。

最佳答案

是的,这是可能的。在您的测试文件 (xxx_test.go) 中创建您自己的 TestMain() 函数,并在组装动态基准案例(结构 testing.InternalBenchmark 的值)后在其中调用testing.Main()正确解析命令行标志,创建并设置testing.M , 并准备并调用 testing.RunBenchmarks() .这样,您的动态基准测试仍然可以通过 go test 运行。

注意:testing.Main() 在调用 os.Exit() 时永远不会返回.如果你想对基准测试结果进行进一步的记录和计算,你也可以调用 testing.MainStart() .Run()(这是 testing.Main() 所做的),您可以传递由 M.Run() 返回的退出代码到 os.Exit()

下面是一个完整的测试文件,您可以使用 go test -bench . 简单地运行它。

输出是:动态生成测试的基准测试结果(具有不同参数的不同实现):

testing: warning: no tests to run
PASS
main.EngineA[impl=0, n=50, x=300]-4 100000 16716 ns/op
main.EngineB[impl=1, n=50, x=300]-4 100000 24788 ns/op
main.EngineA[impl=0, n=50, x=200]-4 100000 10764 ns/op
main.EngineB[impl=1, n=50, x=200]-4 100000 16415 ns/op
main.EngineA[impl=0, n=100, x=300]-4 50000 33426 ns/op
main.EngineB[impl=1, n=100, x=300]-4 30000 48466 ns/op
main.EngineA[impl=0, n=100, x=200]-4 50000 20452 ns/op
main.EngineB[impl=1, n=100, x=200]-4 50000 33134 ns/op
main.EngineA[impl=0, n=500, x=300]-4 10000 163087 ns/op
main.EngineB[impl=1, n=500, x=300]-4 5000 238043 ns/op
main.EngineA[impl=0, n=500, x=200]-4 10000 102662 ns/op
main.EngineB[impl=1, n=500, x=200]-4 10000 163113 ns/op
main.EngineA[impl=0, n=1000, x=300]-4 5000 319744 ns/op
main.EngineB[impl=1, n=1000, x=300]-4 3000 512077 ns/op
main.EngineA[impl=0, n=1000, x=200]-4 10000 201036 ns/op
main.EngineB[impl=1, n=1000, x=200]-4 5000 325714 ns/op
ok _/xxx/src/play 27.307s

和源代码(一个测试文件,例如 dynbench_test.go):

package main

import (
"fmt"
"testing"
)

type Engine interface {
Calc()
}

type EngineA struct{ n, x int }

func (e EngineA) Calc() {
for i := 0; i < e.n; i++ {
a, b := make([]byte, e.x), make([]byte, e.x)
copy(b, a)
}
}

type EngineB struct{ n, x int }

func (e EngineB) Calc() {
for i := 0; i < e.n*2; i++ {
a, b := make([]byte, e.x/2), make([]byte, e.x/2)
copy(b, a)
}
}

func TestMain(m *testing.M) {
implementations := [](func(n, x int) Engine){
func(n, x int) Engine { return EngineA{n, x} },
func(n, x int) Engine { return EngineB{n, x} },
}

benchmarks := []testing.InternalBenchmark{}
for _, n := range []int{50, 100, 500, 1000} {
for _, x := range []int{300, 200} {
for name, gen := range implementations {
impl := gen(n, x)
bm := testing.InternalBenchmark{
Name: fmt.Sprintf("%T[impl=%d, n=%d, x=%d]", impl, name, n, x)}
bm.F = func(b *testing.B) {
for i := 0; i < b.N; i++ {
impl.Calc()
}
}
benchmarks = append(benchmarks, bm)
}
}
}
anything := func(pat, str string) (bool, error) { return true, nil }

testing.Main(anything, nil, benchmarks, nil)
}

注释#2:

testing.Main()testing.MainStart()testing.InternalBenchmark 可能会在未来的版本中更改(或删除)围棋:

An internal function / internal type but exported because it is cross-package; part of or called by the implementation of the "go test" command.

关于testing - 是否可以动态运行基准测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33537552/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com