Profilage d’un programme en Go

Le Go intègre un package permettant la génération par échantillonnage d’un fichier au format de l’outil d’analyse pprof de Google. C’est surtout pour le tester que je l’ai intégré mais en une demi-heure, recherches et installations comprises, j’ai fini par diviser par plus de 8 le temps d’exécution de l’un de mes programmes…

Pour le profiling de votre programme en Go, vous aurez besoin de Graphviz (un paquet est disponible en standard dans la logithèque d’Ubuntu) et de Google perftools (lequel s’installe très bien sous Ubuntu via deux paquets).

La génération du fichier prof se définit en un seul point du programme (grâce entre autre au defer, lequel est si pratique pour éviter les lourds try/finally du java). J’utilise le package flag pour déterminer si j’active le profiling et pour passer le chemin du fichier :

func main() {
    cpuprofile := flag.String("cpuprofile", "", "fichier dans lequel écrire un bilan de profiling cpu")
    flag.Parse()
    if *cpuprofile != "" {
	fmt.Println("Profiling actif, résultats dans le fichier ", *cpuprofile)
        fp, err := os.Create(*cpuprofile)
        if err != nil {
            log.Fatal(err)
        }
        pprof.StartCPUProfile(fp)
        defer pprof.StopCPUProfile()
    }

Après l’exécution de mon programme mapper, j’accède à l’outil via cette commande :

Diverses commandes (list, top20) sont utiles, mais la plus intéressante est la commande web. Celle-ci construit un graphe svg et l’ouvre dans un navigateur. Ce graphe met clairement en évidence les fonctions qui consomment la CPU. Cliquez sur l’image pour visualiser le graphe complet :

cliquez pour voir le graphe

Quelques mots à propos du programme profilé : il s’agit du générateur de cartographie Braldop. Toutes les 4 heures il analyse quelques milliers de fichiers csv pour construire en mémoire une carte du jeu Braldahim qu’il exporte ensuite sous la forme de fichiers json et png. Je ne m’étais jamais trop préoccupé des performances, puisqu’une dizaine de secondes d’occupation de mon serveur toutes les 4 heures, sans interruption de service, n’avaient rien de catastrophique. Je pensais que la charge devait être liée au parsage de tous ces fichiers csv, d’où ma surprise : le graphe indiquait que 75% du temps était passé dans l’encodage des quelques images png. Et une bonne partie des fonctions appelées correspondaient manifestement à des opérations bien trop lourdes (recherche de filtre, de couleur proche, etc.) pour l’encodage d’images ne comptant qu’une trentaine de couleurs différentes.

J’ai rapidement réécrit les quelques lignes de génération de l’image pour travailler sur une image indexée (la palette étant définie a priori) plutôt que sur une image RGBA. Le test montre que l’image est maintenant générée et encodée en 200 ms (sur la brouette sur laquelle je développe) au lieu de 2 secondes.

Le code final de génération de l’image en go est disponible là :

https://github.com/Canop/braldop/blob/master/src/go/braldop/bra/pngCouche.go

Ce code peut intéresser ceux qui ont l’habitude, par exemple, du java, de ses cascades de streams, de ses try/catch, et de sa verbosité générale.

L’outil pprof ressemble aux autres outils de Google : efficace, simple d’utilisation, très sobre, dénué d’enjolivements, peu documenté mais clair. La lisibilité du graphe permet l’analyse immédiate des problèmes de performance.

 

Les commentaires sont fermés.