Функция BenchmarkXxx

BenchmarkXxx - это не самостоятельная функция, а шаблон именования функций бенчмарков в пакете testing. Бенчмарки используются для измерения производительности кода: времени выполнения, количества операций и аллокаций памяти. Функция бенчмарка принимает указатель на testing.B и должна выполняться b.N раз для получения достоверных результатов.

Соглашение об именовании требует, чтобы имя функции бенчмарка начиналось с префикса Benchmark, за которым следует произвольная часть, описывающая тестируемый код. Например, BenchmarkConcat, BenchmarkSortInts или BenchmarkStringBuilder. Функция должна быть экспортируемой (начинаться с заглавной буквы) и иметь сигнатуру func BenchmarkXxx(b *testing.B).

Синтаксис

gofunc BenchmarkXxx(b *testing.B) {
  for i := 0; i < b.N; i++ {
    // код, производительность которого измеряется
  }
}

Внутри тела бенчмарка цикл for с условием i < b.N является обязательным. Именно внутри этого цикла размещается тестируемый код. Поле b.N автоматически подбирается рантаймом для стабильных результатов.

Пример 1

Давайте создадим бенчмарк для сравнения конкатенации строк через оператор +:

gopackage main

import (
  "testing"
)

func BenchmarkConcat(b *testing.B) {
  for i := 0; i < b.N; i++ {
    s := "Hello" + " " + "World"
    _ = s
  }
}

Запуск бенчмарка выполняется командой go test -bench=:

go"go test -bench=BenchmarkConcat"

Результат выполнения бенчмарка:

go"BenchmarkConcat-8  1000000000  0.0000009 ns/op"

В выводе мы видим: имя бенчмарка с указанием числа ядер процессора (-8), количество итераций (1000000000) и среднее время на одну операцию (0.0000009 ns/op).

Пример 2

Рассмотрим бенчмарк, который использует b.ResetTimer() для сброса таймера после подготовительных операций:

gopackage main

import (
  "strings"
  "testing"
)

func BenchmarkBuilder(b *testing.B) {
  var sb strings.Builder
  b.ResetTimer()
  for i := 0; i < b.N; i++ {
    sb.WriteString("Hello")
  }
}

Результат выполнения бенчмарка:

go"BenchmarkBuilder-8  30000000  45.2 ns/op"

Метод b.ResetTimer() позволяет исключить время на подготовку данных, измеряя только производительность тестируемого кода.

Пример 3

Используем b.ReportAllocs() для отображения информации о выделении памяти в бенчмарке:

gopackage main

import (
  "testing"
)

func BenchmarkAlloc(b *testing.B) {
  b.ReportAllocs()
  for i := 0; i < b.N; i++ {
    s := make([]int, 10, 20)
    _ = s
  }
}

Результат выполнения бенчмарка с аллокациями:

go"BenchmarkAlloc-8  50000000  24.8 ns/op  128 B/op  1 allocs/op"

В выводе добавились два столбца: выделенная память на операцию (128 B/op) и количество аллокаций (1 allocs/op).

Смотрите также

  • тип testing.B,
    который предоставляет методы для управления бенчмарками
  • метод testing.B.N,
    который определяет количество итераций в бенчмарке
  • метод testing.B.ResetTimer,
    который сбрасывает таймер бенчмарка
  • метод testing.B.ReportAllocs,
    который включает отчет по аллокациям памяти