27/100 Dias de Golang - Testes de benchmark
Table of Contents
#
Benchmarking em Go: Medindo e Otimizando o desempenho
Como você deve ter visto até aqui, testes em go são muito simples e a biblioteca padrão nos oferece recursos bem poderosos. Outra ferramenta que a biblioteca testing
oferece de forma nativa é o benchmarking
. O benchmarking serve para diversas finalidades, todas relacionadas à avaliação e otimização do desempenho de sistemas, aplicações, algoritmos ou componentes de software. A questão mais legal que eu achei foi a comparação de implementações, testar qual implementação de uma função performa melhor que outra. Veja como é simples fazer esses testes:
func BenchmarkExemplo(b *testing.B) {
for i := 0; i < b.N; i++ {
// código a ser medido
}
}
A principal diferença é que passamos de parâmetro o b *testing.B
, nos testes unitários passamos t *testing.T
. Dentro da função fazemos um loop passando i < b.N
esse N
será o número de execuções da função.
Vamos adicionar uma nova função na nossa “biblioteca” utils.go
. Essa função será a SomaComLoop
, passamos um int
e ela retorna a soma de todos os números de n até 1. Curiosidade: Isso, na matemática, se chama “Termial” e é representado pelo símbolo “?” 3? = 3 + 2 + 2 = 6
func SomaComLoop(n int) int {
sum := 0
for i := 1; i <= n; i++ {
sum += i
}
return sum
}
E vamos criar um benchmark para ela:
func BenchmarkSomaComLoop(b *testing.B) {
for i := 0; i < b.N; i++ {
SomaComLoop(10000)
}
}
Veja a saída:
goos: linux
goarch: amd64
pkg: firsttest
cpu: Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz
BenchmarkSomaComLoop-4 169431 6882 ns/op
PASS
ok firsttest 2.230s
Agora vamos fazer uma otimização nesse código e fazer a soma utilizando uma fórmula:
func SomaComFormula(n int) int {
return (n * (n + 1)) / 2
}
e criar o benchmark
func BenchmarkSomaComFormula(b *testing.B){
for i := 0; i< b.N; i++ {
SomaComFormula(10000)
}
}
Saída:
goos: linux
goarch: amd64
pkg: firsttest
cpu: Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz
BenchmarkSomaComFormula-4 1000000000 0.3671 ns/op
PASS
ok firsttest 0.425s
Agora rodando o com a flag -benchmem
para obtermos informações sobre a memória dos testes:
go test -bench=. -benchmem
Veja o resultado:
goos: linux
goarch: amd64
pkg: firsttest
cpu: Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz
BenchmarkSomaComLoop-4 175250 6874 ns/op 0 B/op 0 allocs/op
BenchmarkSomaComFormula-4 1000000000 0.3457 ns/op 0 B/op 0 allocs/op
PASS
ok firsttest 2.677s
No começo temos informações sobre a plataforma que estamos rodando mas o interessante são as comparações entra as funções:
BenchmarkSomaComLoop-4 175250 6874 ns/op 0 B/op 0 allocs/op
BenchmarkSomaComFormula-4 1000000000 0.3457 ns/op 0 B/op 0 allocs/op
O primeiro valor 175250
e 1000000000
representa o b.N
do loop. Esse valor é ajustado pelo compilador para encontrar uma amostra com dados significativos. Veja que a função com loop foi executada 175.250 vezes enquanto a com a fórmula foi executada 1 bilhão de vezes.
O segundo valor é o tempo médio que cada operação levou. Na com loop: 6874 nanossegundos
(ou 6,874 microssegundos), com fórmula: 0.3457 nanossegundos
O terceiro e o quarto valor são referentes a quantidade de memória alocada e o número alocações. No nosso exemplo não tivemos esse valor.
Olhando os resultados me lembrei das aulas de Análise de Algoritmos, a função SomaComFormula
é de complexidade O(1) ou constante, enquanto a SomaComLoop
é O(n).
Muito interessante essa ferramenta nativa do Go para testarmos nossas funções!