Introduction : pourquoi le profilage n'est pas un luxe, mais une nécessité
\nChaque développeur C++ a déjà été confronté à une situation où le programme fonctionne, mais lentement. Les suppositions intuitives sur la partie du code qui « ralentit » s'avèrent souvent erronées. Sans données précises, vous risquez d'optimiser ce qui fonctionne déjà rapidement, en négligeant les véritables « goulots d'étranglement ». Le profilage est la seule méthode scientifique pour mesurer les performances et trouver les goulots d'étranglement.
\nDans cet article, nous allons examiner trois outils puissants pour le profilage du code C++ : gprof (statistique), Perf (matériel) et Valgrind/Callgrind (simulation). Vous apprendrez à les utiliser en pratique, à interpréter les résultats et à trouver rapidement les zones problématiques.
1. Profilage statistique avec gprof : démarrage rapide
\ngprof est un profileur GNU classique qui fonctionne par échantillonnage statistique. Il ne nécessite pas de droits spéciaux et est idéal pour une première analyse.
Comment préparer le code
\nPour utiliser gprof, vous devez compiler le programme avec les options -pg et -g :
g++ -pg -g main.cpp -o my_program\n./my_program\nAprès l'exécution du programme, un fichier gmon.out apparaît dans le dossier courant. Pour obtenir un rapport lisible, exécutez :
gprof my_program gmon.out > report.txt\n\nExemple : trouver un algorithme lent
\nConsidérons un programme simple qui trie un tableau de deux manières :
\n#include <iostream>\n#include <vector>\n#include <algorithm>\n#include <chrono>\n\nvoid bubble_sort(std::vector<int>& arr) {\n for (size_t i = 0; i < arr.size(); ++i)\n for (size_t j = 0; j < arr.size() - i - 1; ++j)\n if (arr[j] > arr[j+1])\n std::swap(arr[j], arr[j+1]);\n}\n\nvoid quick_sort_wrapper(std::vector<int>& arr) {\n std::sort(arr.begin(), arr.end());\n}\n\nint main() {\n std::vector<int> data(50000);\n std::generate(data.begin(), data.end(), std::rand);\n \n auto copy1 = data;\n auto copy2 = data;\n \n bubble_sort(copy1);\n quick_sort_wrapper(copy2);\n \n return 0;\n}\nLancez le profilage. Dans le rapport gprof, vous verrez un tableau d'appels. bubble_sort occupera 95 à 99 % du temps. C'est un goulot d'étranglement évident : remplacer le tri à bulles par std::sort donnera un gain immédiat.
Interprétation des résultats
\nDans le rapport, cherchez la colonne % time — elle indique la proportion de temps passée dans la fonction. Les fonctions avec un pourcentage élevé sont vos candidates à l'optimisation.
\n\n2. Profilage matériel avec Perf : précision au cycle près
\nPerf est un outil moderne pour Linux qui utilise les compteurs matériels du CPU. Il a une surcharge minimale et permet de mesurer non seulement le temps, mais aussi les défauts de cache, les mauvaises prédictions de branchement et d'autres métriques.
Installation et utilisation de base
\nsudo apt install linux-tools-common linux-tools-generic # Ubuntu/Debian\nperf stat ./my_program # Statistiques générales\nperf record ./my_program # Enregistrement du profil\nperf report # Visualisation du rapport\n\nExemple : trouver les défauts de cache
\nSupposons que nous ayons une fonction qui traite une matrice ligne par ligne :
\nconst int N = 4096;\nint matrix[N][N];\n\nvoid process_rows() {\n for (int i = 0; i < N; ++i)\n for (int j = 0; j < N; ++j)\n matrix[i][j] *= 2;\n}\n\nvoid process_cols() {\n for (int j = 0; j < N; ++j)\n for (int i = 0; i < N; ++i)\n matrix[i][j] *= 2;\n}\nExécutez perf stat pour chaque fonction. Vous verrez que process_cols a un ordre de grandeur de cache-misses en plus. La raison