Перейти к основному содержимому
Модуль 9 · Урок 3 из 543/50 в курсе~12 min
Уроки модуля (3/5)

Тесты и профили

Помимо функциональных тестов, go test также имеет встроенные тесты (BenchmarkXxx) и поддерживает профили ЦП и памяти (pprof). Все без внешних зависимостей.

Форма эталона

Go
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.

Типичные команды

Bash
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

Типичный результат:

Code
BenchmarkSum-8        1000000000        0.31 ns/op

-8 — это значение GOMAXPROCS. 0.31 ns/op — среднее время одного звонка.

Дорогая установка: b.ResetTimer

Если у вас долгий этап подготовки перед циклом, исключите его из измерения:

Go
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 для параметрических тестов:

Go
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

Bash
go test -bench=. -count=10 > old.txt
# apply change
go test -bench=. -count=10 > new.txt
benchstat old.txt new.txt

benchstat (в golang.org/x/perf/cmd/benchstat) вычисляет среднее значение, стандартное отклонение и статистическую значимость разницы.

Упражнения

Упражнение#go.m9.l3.e1
Попыток: 0Загрузка…

Определите BenchmarkSum с помощью цикла над b.N, который вызывает Sum(2, 3).

Загрузка редактора…

Решение доступно после 3 попыток

Упражнение#go.m9.l3.e2
Попыток: 0Загрузка…

Добавьте b.ResetTimer ПОСЛЕ дорогостоящей настройки, перед циклом, чтобы настройка не учитывалась в измерении.

Загрузка редактора…

Решение доступно после 3 попыток

Quiz#go.m9.l3.e3
Готово

Какой флаг запускает все тесты в пакете?

Go
$ go test ???
Варианты ответа