稳定的测试环境

性能测试受环境影响很大,为保证测试的可重复性,尽可能地保持测试环境的稳定

  • 机器处于闲置状态,测试时不要执行其他任务,也不要和其他人共享硬件资源
  • 机器是否关闭了节能模式,一般笔记本会默认打开这个模式,测试时关闭
  • 避免使用虚拟机和云主机进行测试,虚拟机和云主机 CPU 和内存一般会超分配,性能表现会非常地不稳定

规则

  • 测试函数需要位于 *_test 文件中
  • 函数名称必须以 Benchmark 开头
  • 函数必须接受 *testing.B 作为唯一形参
  • 测试函数必须包含一个 for 循环( b.N 为其上限,b.N, go 会根据系统情况生成)
// fib.go
package main

func Fib(n int) int {

	if n == 0 || n == 1 {
		return n
	}
	return Fib(n-2) + Fib(n-1)
}
// fib_test.go
package main

import "testing"

func BenchmarkFib(b *testing.B) {
	for n := 0; n < b.N; n++ {
		Fib(30) // run fib(30) b.N times
	}
}

默认 go test 会运行单元测试,可以使用-run=匹配一个从来没有的单元测试方法,过滤掉单元测试的输出(如 -run=^$)

go test -run=XXX -bench=. -benchmem -cpuprofile cpu.out -memprofile mem.out

benchmark 默认至少运行1秒。 -benchtime=Ns 指定具体运行时间

-count=N 表示运行该基准测试多少次。注意:不是多少次op或迭代

函数名后的数字表示 GOMAXPROCS 的值,默认是 CPU 的核数。该值可以在执行测试时设置,例如 GOMAXPROCS=2 go test ...

benchstat

go install golang.org/x/perf/cmd/benchstat@latest
package main
import "testing"
//go:noinline
func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}
var Result int
func BenchmarkMax(b *testing.B) {
    var r int
    for i := 0; i < b.N; i++ {
        r = max(-1, i)
    }
    Result = r
}
go test -bench=.  -count=10  -gcflags="-l -N"  > base.txt
go test -bench=.  -count=10  > noinline.txt
go test -bench=.  -count=10  > inline.txt
benchstat base.txt noinline.txt  inline.txt
goos: windows
goarch: amd64
pkg: test
cpu: 13th Gen Intel(R) Core(TM) i5-13600KF
       │   base.txt   │             noinline.txt             │              inline.txt              │
       │    sec/op    │    sec/op     vs base                │    sec/op     vs base                │
Max-20   0.9940n ± 1%   0.4947n ± 1%  -50.23% (p=0.000 n=10)   0.1358n ± 1%  -86.33% (p=0.000 n=10)

如果 delta 一列,值是~,没有显示百分比,说明两次测试结果没有显著差异

go test -cover

ref

The Cover Story