Introduction : pourquoi le profilage du code Go est un must have
Le développement en Go (Golang) est réputé pour ses performances et son efficacité. Cependant, même le code le plus rapide peut ralentir si l'on ne tient pas compte des particularités de la gestion de la mémoire, des goroutines ou des entrées-sorties. Le profilage est le processus de collecte de données sur l'exécution d'un programme, qui permet de regarder « sous le capot » et de comprendre quelles fonctions consomment le plus de CPU, de mémoire ou de temps.
Dans cet article, nous allons examiner les outils pratiques de profilage en Go : pprof, trace et les benchmarks intégrés. Vous apprendrez à trouver les goulots d'étranglement et à optimiser le code sur des exemples concrets.
1. Outils de profilage principaux en Golang
Go fournit un arsenal puissant pour le profilage directement prêt à l'emploi. Examinons trois approches clés :
- pprof — profilage du CPU, de la mémoire, des verrous et des goroutines.
- trace — traçage des événements : création de goroutines, appels système, GC.
- benchmark — test de performance intégré avec
go test -bench.
Pour commencer avec pprof, il suffit d'importer net/http/pprof dans votre serveur HTTP ou d'utiliser runtime/pprof pour les applications CLI.
1.1. Comment lancer le profilage CPU
La méthode la plus simple consiste à ajouter un endpoint à votre serveur HTTP :
package main
import ( "log" "net/http" _ "net/http/pprof")
func main() { go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }() // votre code principal select {}}Après le lancement, ouvrez http://localhost:6060/debug/pprof/ — vous verrez un tableau de bord. Pour collecter un profil CPU pendant 30 secondes, exécutez :
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30Cela téléchargera les données et ouvrira la console interactive pprof.
2. Trouver les goulots d'étranglement avec pprof : CPU et mémoire
Supposons que nous ayons une fonction qui traite un grand tableau de données. Nous soupçonnons qu'elle ralentit. Écrivons un exemple de test et profilons-le.
2.1. Exemple de code lent
package main
import ( "fmt" "time")
func slowFunction(data []int) int { sum := 0 for _, v := range data { time.Sleep(1 * time.Microsecond) // simulation de travail sum += v * v } return sum}
func main() { data := make([]int, 100000) for i := range data { data[i] = i } result := slowFunction(data) fmt.Println(result)}Lançons le profilage CPU :
go run main.go &go tool pprof -http=:8080 http://localhost:6060/debug/pprof/profile?seconds=10Dans le navigateur, une visualisation s'ouvrira — un graphe d'appels (call graph). L'épaisseur des arêtes montre le temps pris par chaque fonction. Nous verrons immédiatement que slowFunction et time.Sleep sont les principaux consommateurs de CPU.
2.2. Analyse de la mémoire (heap profile)
Pour trouver les fuites mémoire ou les objets qui prennent trop de place, utilisez :
go tool pprof http://localhost:6060/debug/pprof/heapDans la console interactive, vous pouvez exécuter la commande top :
(pprof) top10Showing nodes accounting for 80MB, 100% of 80MB total flat flat% sum% cum cum% 40MB 50.00% 50.00% 40MB 50.00% main.slowFunction 20MB 25.00% 75.00% 20MB 25.00% main.createLargeSlice 20MB 25.00% 100.00% 20MB 25.00% runtime.makesliceCela montre quelles fonctions allouent le plus de mémoire. Si vous voyez que main.slowFunction alloue 40MB, il faut envisager un refactoring — par exemple, utiliser la réutilisation de sli