Introduction : pourquoi profiler le code Rust ?
\n\nRust est réputé pour sa vitesse et sa sécurité, mais même le code le plus rapide peut être lent s'il contient des goulots d'étranglement. Le profilage est le processus de mesure des performances d'un programme : temps d'exécution, charge CPU, mémoire et autres métriques. Pour les développeurs débutants en Rust, c'est une compétence indispensable qui permet de transformer un code « qui fonctionne juste » en un code efficace et rapide.
\n\nImaginez que vous ayez écrit un analyseur de logs ou un jeu en Rust. Tout compile, mais le programme met plus de temps que prévu à s'exécuter. Au lieu de deviner quelle partie du code ralentit, vous pouvez utiliser des profileurs qui montreront précisément les « points chauds » (hotspots). Dans cet article, nous allons explorer les outils de profilage Rust de base pour les débutants : cargo-flamegraph, perf et les mesures simples avec std::time::Instant.
1. La méthode la plus simple : mesurer le temps avec std::time::Instant
\n\nAvant de passer à des outils complexes, apprenez à mesurer le temps d'exécution de sections de code individuelles. C'est une méthode basique mais efficace pour les débutants.
\n\nExemple : mesurer le temps d'exécution d'une fonction
\n\nuse std::time::Instant;\n\nfn slow_function() {\n let mut sum = 0u64;\n for i in 0..1_000_000 {\n sum += i;\n }\n println!("Somme : {}", sum);\n}\n\nfn main() {\n let start = Instant::now();\n slow_function();\n let duration = start.elapsed();\n println!("Temps d'exécution : {:?}", duration);\n}\n\n\nCe code affichera le temps exact d'exécution de slow_function. Cependant, cette approche n'est pas pratique pour les grands projets : vous devrez placer manuellement des mesures à chaque endroit suspect.
Quand est-ce utile ?
\n- \n
- Vous voulez vérifier rapidement une hypothèse concernant une fonction lente. \n
- Vous ne pouvez pas installer d'outils supplémentaires. \n
- Vous travaillez avec du code monothread sans logique complexe. \n
Inconvénient : les mesures manuelles ne montrent pas le temps passé à l'intérieur des fonctions appelées (par exemple, les allocations mémoire ou les appels système). Pour cela, vous avez besoin de profileurs.
\n\n2. Profilage avec perf (Linux)
\n\nL'utilitaire perf est un profileur puissant pour Linux qui fonctionne au niveau du noyau. Il collecte des échantillons (samples) de l'endroit où le programme passe son temps. Pour commencer, assurez-vous que perf est installé :
sudo apt install linux-tools-common linux-tools-generic # Ubuntu/Debian\n\n\nÉtape 1 : Compilation avec les informations de débogage
\nPour que perf puisse afficher les noms de fonctions et les numéros de ligne, compilez votre projet en mode debug (ou release avec les flags debuginfo) :
cargo build\n# ou\nRUSTFLAGS="-g" cargo build --release\n\n\nÉtape 2 : Lancement du profilage
\nperf record -g ./target/debug/votre_programme\nperf report\n\n\nLe flag -g active l'enregistrement de la pile d'appels (call graph). Après avoir exécuté perf report, vous verrez une liste interactive de fonctions, triée par temps d'exécution.
Exemple d'interprétation
\nSupposons que vous voyiez que 70 % du temps est pris par la fonction Vec::push. Cela peut signifier que vous réallouez fréquemment de la mémoire. Solution : allouer la capacité du vecteur à l'avance avec Vec::with_capacity.
Conseil : Pour les débutants, perf peut sembler complexe en raison de l'abondance de données. Commencez par perf top en temps réel pour voir quelles fonctions « chauffent » immédiatement.
3. Visualisation avec cargo-flamegraph
\n\nSi vous avez besoin d'une représentation visuelle claire, utilisez cargo-flamegraph. Cet outil génère des flamegraphs — des graphiques où la largeur d'un rectangle représente le temps d'exécution d'une fonction, et la profondeur l'appel