Уроки модуля (3/5)
Тесты и профили
Помимо функциональных тестов, go test также имеет встроенные тесты (BenchmarkXxx) и поддерживает профили ЦП и памяти (pprof). Все без внешних зависимостей.
Форма эталона
func BenchmarkSum(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = Sum(2, 3)
}
}Характеристики:
- Точная подпись:
func BenchmarkXxx(b *testing.B). – Цикл должен выполнитьb.Nитераций: платформа автоматически корректируетb.N, начиная с 1 и увеличивая до тех пор, пока измерение не стабилизируется (~1 секунда по умолчанию). - Результат:
ns/op(наносекунд на операцию), а с-benchmemтакжеB/opиallocs/op.
Типичные команды
go test -bench=. ./... # all benchmarks
go test -bench=Sum -benchmem # only Sum, with memory info
go test -bench=. -benchtime=5s # each benchmark for 5 seconds
go test -bench=. -cpuprofile=cpu.out # generate a CPU profileТипичный результат:
BenchmarkSum-8 1000000000 0.31 ns/op
-8 — это значение GOMAXPROCS. 0.31 ns/op — среднее время одного звонка.
Дорогая установка: b.ResetTimer
Если у вас долгий этап подготовки перед циклом, исключите его из измерения:
func BenchmarkSearch(b *testing.B) {
data := buildLargeSlice(1_000_000) // expensive
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = Search(data, 42)
}
}Полезные варианты:
b.StopTimer()/b.StartTimer()— приостановить измерение на неинтересной фазе (удобно внутри цикла).b.ReportAllocs()— отчет о принудительном распределении даже без-benchmem.
Таблица сравнения с b.Run
Как и t.Run для тестов, существует b.Run для параметрических тестов:
func BenchmarkSplit(b *testing.B) {
for _, size := range []int{10, 1000, 100000} {
b.Run(fmt.Sprintf("n=%d", size), func(b *testing.B) {
s := strings.Repeat("a,", size)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = strings.Split(s, ",")
}
})
}
}Выходные строки, такие как BenchmarkSplit/n=10-8, BenchmarkSplit/n=1000-8, ... идеально подходят для масштабирования диаграмм.
Сравнение двух реализаций с benchstat
go test -bench=. -count=10 > old.txt
# apply change
go test -bench=. -count=10 > new.txt
benchstat old.txt new.txtbenchstat (в golang.org/x/perf/cmd/benchstat) вычисляет среднее значение, стандартное отклонение и статистическую значимость разницы.
Упражнения
Определите BenchmarkSum с помощью цикла над b.N, который вызывает Sum(2, 3).
Решение доступно после 3 попыток
Добавьте b.ResetTimer ПОСЛЕ дорогостоящей настройки, перед циклом, чтобы настройка не учитывалась в измерении.
Решение доступно после 3 попыток
Какой флаг запускает все тесты в пакете?
$ go test ???