@MrKMV34
Превозмогая трудности

Golang Benchmark почему разные результаты?

Здравствуйте

Изучаю язык go и добрался до использования бенчмарков.
У меня есть модуль popcount (да, из книги The Go Programming Language) в нём 4 функции.
go версии 1.6, пишу в intellij idea 2016

Сам вопрос, если я запускаю тест, чтобы проверить время работы функции, то у меня результаты
PASS
BenchmarkPopCount1-8            200000000                6.57 ns/op
BenchmarkPopCountByLoop-8       100000000               13.0 ns/op
BenchmarkPopCountByShifting-8   20000000                63.9 ns/op
BenchmarkPopCountByClearing-8   1000000000               2.41 ns/op
ok      github.com/user/popcount        9.110s

А если я запуская тестирования на покрытие, то результаты
PASS
BenchmarkPopCount1-8         	100000000	        13.0 ns/op
BenchmarkPopCountByLoop-8    	20000000	        79.6 ns/op
BenchmarkPopCountByShifting-8	 1000000	      1079 ns/op
BenchmarkPopCountByClearing-8	50000000	        27.6 ns/op
coverage: 100.0% of statements
ok  	github.com/user/popcount	7.157s


С чем может быть связан такой большой рост времени у функции BenchmarkPopCountByShifting?
её код
func PopCountByShifting(x uint64) int {
	n := 0
	shifted := x
	for i := uint(0); i < 64; i++ {
		// get left byte
		if ((shifted & 1) == 1) {
			n++
		}
		shifted >>= 1
	}
	return n
}
  • Вопрос задан
  • 1330 просмотров
Решения вопроса 1
@mantyr
Пишу много Golang кода с удовольствием:)
Во время подсчёта "покрытия" часть ресурсов тратится на эту задачу и она не обязательно должна быть эффективной. По этому бенчмарк в это время ресурсов недополучает и вообще может показывать не корректные замеры так как фоновые процедуру могут выполняться и нагружать CPU не равномерно.

При бенчмарке желательно:
  • что бы нигде ничего не было запущено
  • что бы нигде ничего не работало в фоне
  • что бы не нужные куски кода были отделены от таймера (например не нужные инициализации, подготовка данных)

Нужны ли бенчмарки? Бенчмарки нужны что бы отбраковать совсем плохие результаты или выбрать между двумя очень похожими. Так же они дают представление о том сколько тратится на каждую итерацию того кода что вы тестируете.

Пример простого бенчмарка с инициализацией вынесеной за таймер:

package conf // <-- здесь название библиотеки для которой предназначены бенчмарки

import (
    "testing"
)

func BenchmarkLoadGo(b *testing.B) {
    conf := NewConfig()
    conf.SetDefaultFile("properties")
    conf.SetDefaultCatalog("./testdata") // default "./configs"

    b.ResetTimer() // <-- обнуляем таймер что бы вся "сложная" и "единомоментная" работа не попала в подсчёт

    for i := 0; i < b.N; i++ {
        go conf.GetSection("server_1", "storage") // <-- в данном случае тестируется сценарий в конкурентном виде, но чаще всего этого не требуется и конкретно в том коде откуда взят бенчмарк есть отдельный бенч для не конкурентного доступа и сравнивая их можно иметь представление о том как оно себя поведёт в обоих сценариях.
    }
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@spotifi
А кто гарантирует, что разные вещи будут давать одинаковые результаты?

Насколько помню:

Для оценки покрытия утилита берет исходный код, копирует его во временный каталог, встраивает внутрь свои вызовы....
То есть это не тот же исходный код уже.

Бенчмарки нужны для того, чтобы найти самое узкое место в программе. То есть только для относительных замеров программы с самой собой, с той же программой, запущенной/скопилированной в точности в тех же условиях. А не для того чтобы получить некие абсолютные цифры, которые годятся для сравнения с чем то другим.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы