Analizar el rendimiento de una aplicación Go(lang)


A veces, es necesario analizar el rendimiento de nuestra aplicación para que funcione más rápido o simplemente para que no se caiga después de un tiempo debido a un memory leak.

Afortunadamente, Go ya incluye herramientas para depurar estos problemas de manera nativa, una de esas es el paquete pprof, el cual genera un formato estándar que puede ser interpretado por diferentes aplicaciones y hasta puede ser graficado.

Para analizar este código usaremos el paquete github.com/pkg/profile para simplificar la integración con pprof:

go get -u -v github.com/pkg/profile

Y para visualizar el resultado usaremos diago:

go get -u -v github.com/remeh/diago

Después de instalar las herramientas que necesitamos, supongamos el siguiente código:

func buildArray(size int) []int {
	arr := make([]int, 0)
	for i := 0; i < size; i++ {
		arr = append(arr, size)
	}

	return arr
}

Ahora escribamos un benchmark para hacer analizar el uso de CPU:

func Benchmark_buildArray(b *testing.B) {
	defer profile.Start(profile.CPUProfile).Stop()

	for i := 0; i < b.N; i++ {
		_ = buildArray(10_000_000)
	}
}

y ahora corramos el benchmark:

go test -bench buildArray .

Después de terminar veremos en la terminal algo como:

2020/03/22 10:25:33 profile: cpu profiling disabled, /ruta/a/un/archivo.pprof

que podremos visualizar con diago:

diago -file /ruta/a/un/archivo.pprof

Lo que mostraría algo así:

Para evitar que buildArray crezca el slice todo el tiempo se puede reservar memoria desde el principio:

...
arr := make([]int, 0, size)
...

Si nos interesa analizar el uso de memoria podemos cambiar el profiler así:

func Benchmark_buildArray(b *testing.B) {
	defer profile.Start(profile.MemProfile).Stop()

	for i := 0; i < b.N; i++ {
		_ = buildArray(10_000_000)
	}
}

Con el siguiente resultado:

En este caso es claro que la función está creando un array gigante pero en muchos casos no es tan fácil de ver y ahí es dónde este método sirve de gran ayuda.


Ver también