til/Development/Go/testing.md

1.4 KiB

testing

Benchmark

Any benchmark should be careful to prevent compiler optimization.

Example calc.go in package calc:

package calc

import (
	"time"
)

var input float64

func init() {
	if time.Now().Year() > 1900 {
		input = 426942694269
	}
}

func calc() int {
	x := input
	x /= 6.9
	x /= 4.2
	x /= 6.9
	x /= 4.2
	return int(x)
}

Example calc_test.go in package calc:

package calc

import (
	"runtime"
	"testing"
)

func BenchmarkX(b *testing.B) {
	for i := 0; i < b.N; i++ {
		calc()
	}
}

var sink int

func BenchmarkCalcSink(b *testing.B) {
	var result int
	for i := 0; i < b.N; i++ {
		result = calc()
	}

	// prevent compiler optimization
	sink = result
}

func BenchmarkCalcKeepAlive(b *testing.B) {
	for i := 0; i < b.N; i++ {
		result := calc()

		// prevent compiler optimization
		runtime.KeepAlive(result)
	}
}

Benchmark result when run with go test -bench=.

goos: linux
goarch: amd64
BenchmarkCalc-4                 1000000000               0.343 ns/op
BenchmarkCalcSink-4             229652618                5.30 ns/op
BenchmarkCalcKeepAlive-4        225297381                5.27 ns/op

BenchmarkCalc is fast because it has compiler optimization.

There are 2 methods for preventing compiler optimization: sink (BenchmarkCalcSink) or keep alive (BenchmarkCalcKeepAlive).