What is

Benchmark是Go testing测试框架提供的基准测试功能,能对一段代码进行性能测试。

下面是一段性能测试的结果:
image.png
Go Benchmark提供的参数包括(按照结果的先后顺序):

  • 重复测试次数:该指标越高,结果越可靠
  • 单次重复的平均耗时:xxx纳秒每次操作,越低越好
  • Heap Memory:每次的内存分配,越低越好
  • 单次测试的内存分配次数:越低越好

使用Benchmark可以做许多测试,比如测试时间复杂度,就可以根据Benchmark的指标随着次数的增长的比例来判断。

How to use

1 Before Use

首先要注意的是,要尽量保证测试环境的稳定。否则,你重复测试的结果是没有可比性的。通常可以通过一下方式使得环境趋于稳定:

  • 当前机器处于闲置状态,不执行其他任务,也不要共享硬件资源
  • 避免使用虚机和进行测试。通常,为了提高资源利用率,虚拟机和云主机CPU和内存会超分配,导致性能不稳定

    关于云主机超分:通常是超售CPU能力,比如,当你的CPU长时间闲置时,也许你的性能会被二次销售给别人。可以通过Linux上Steal Time的指标来衡量自己被偷走的CPU占用时间

2 Case

我们就简单地,测试一下Go语言字符串的拼接方式。

  1. _test.go文件中,写Benchmark测试函数

    1. func BenchmarkPlus(b *testing.B) {
    2. var str string
    3. for n := 0;n < b.N; n++ {
    4. str += "helloMyWorld"
    5. }
    6. }
    • Benchmark也在_test.go文件中,使用的是TB中的B
    • 函数名以Benchmark开头,B.N表示的是用例测试的次数,这个是自动定的
  2. 使用go test -bench <module name>/<package name>运行性能测试用例,模块名和包名可选。且-bench参数支持正则表达式,仅执行匹配的测试,如-bench='Fib$'

    1. $ go test -bench=. -benchmem
    2. goos: darwin
    3. goarch: amd64
    4. pkg: try
    5. cpu: VirtualApple @ 2.50GHz
    6. BenchmarkPlus-8 148148 82902 ns/op 892933 B/op 1 allocs/op
    7. PASS
    8. ok try 12.453s
    • BenchmarkPlus-8中的-8,是GOMAXPROCS,默认等于CPU核数,可以使用-cpu=2,4的形式进行修改。CPU的核数主要影响设计并行的函数
    • -benchmem用于查看内存分配的信息
    • -benchtime=10s设置测试时间(实际执行时间因为还有编译、执行、销毁等阶段,会大于这个时间),-benctime=10x可以设置次数,-count可以设置Benchmark的轮数

3 Details

通常,我们只想关注我们核心代码的性能情况,而性能测试所统计的时间会包括编译、用例的准备销毁等开销,所以可以使用内置的方法来忽略掉这些开销。当然,由于循环的部分是我们自己实现的,所以这部分的开销通常是不会很大的,所以我觉得,可能意义不那么明显。

B.ResetTimer()

重置计时器,字面意思,很好理解。在你的测试代码前使用,就可以忽略掉准备的时间

B.StopTimer & StartTimer()

停止、开始计时,自己酌情使用

B.SetBytes()

该函数用于设置字节数,感觉使用频率会非常的低,可以去《Go专家编程》中看看更详细的用例

Deeper

1 B.N

首先是基准测试的循环次数B.N,这个并不是由我们手动设置的,而是由内置的函数进行测算的。相关的伪代码仍然可以在专家编程中看到,这里就简述一下思想:

  • 先进行一次测试,在测试正确的情况下,衡量单次测试的时长
  • 如果时长较短,将测试更多的次数,较长则较少。最终会定格为10的指数级,方便查看
  • 默认情况下,最少要执行测试1秒,最多不超过1e9次

    Reference

    Special

    感谢五月天的歌曲,为本次学习带来的动力