Votre code C++ est lent ? Il est temps de regarder sous le capot
\n\nVous avez écrit un code C++ qui semble parfait. La compilation s'est déroulée sans erreur, le programme se lance... mais il tourne au ralenti. Cela vous dit quelque chose ? L'envie vous prend de tout réécrire en assembleur ou d'ajouter du multithreading en urgence. Ne vous précipitez pas. Le problème ne vient probablement pas de l'architecture, mais de quelques fonctions « gourmandes » qui monopolisent 90 % du temps processeur.
\n\nDans le monde Linux, nous disposons d'un arsenal d'outils puissants pour le profilage de code C++. Ce n'est pas de la magie, c'est de la science. On ne devine pas, on mesure. Dans ce guide, je vais vous montrer quatre approches concrètes : du rapide « survol » au micro-benchmarking. Vous apprendrez comment profiler du C++ sous Linux comme un véritable expert.
\n\nPourquoi les suppositions sont nuisibles et le profilage est bénéfique
\n\nAvant de plonger dans le code, retenez la règle d'or de l'optimisation : « N'optimisez pas ce que vous n'avez pas mesuré ». Votre intuition est un mauvais conseiller. On passe souvent des heures à optimiser une fonction appelée une fois par minute, tout en ignorant une simple boucle de 10 millions d'itérations.
\n\nLe profilage répond à trois questions essentielles :
\n- \n
- Où le programme passe-t-il le plus de temps ? \n
- Pourquoi cela se produit-il (algorithme inefficace, nombreuses opérations d'entrée-sortie, défauts de cache) ? \n
- Qu'est-ce qui a changé après vos modifications ? \n
Aujourd'hui, nous allons décortiquer quatre outils qui couvriront 99 % de vos besoins. C'est parti !
\n\nOutil n°1 : gprof — le classique indémodable
\n\ngprof est le bon vieux profileur GNU intégré. Il fonctionne en deux étapes : la collecte de statistiques pendant l'exécution du programme, puis leur analyse. Avantages : rien à installer, présent dans toutes les distributions. Inconvénients : donne des résultats approximatifs et ne gère pas nativement les programmes multithreadés.
\n\nComment utiliser gprof
\n\nÉtape 1. Compilez le programme avec le drapeau spécial -pg :
g++ -pg -O2 my_program.cpp -o my_program\n\nNotez que nous utilisons -O2. Profiler une version de débogage sans optimisations n'a pas de sens : vous obtiendrez une image faussée.
Étape 2. Lancez le programme. Il s'exécutera un peu plus lentement car gprof collecte les données.
\n./my_program\n\nÉtape 3. Un fichier gmon.out apparaît dans le dossier courant. Analysez-le :
gprof my_program gmon.out > analysis.txt\n\nOuvrez analysis.txt et vous verrez quelque chose comme :
Flat profile:\nEach sample counts as 0.01 seconds.\n % cumulative self self total\n time seconds seconds calls us/call us/call name\n 60.00 0.06 0.06 10000 6.00 6.00 slow_function\n 20.00 0.08 0.02 5000 4.00 4.00 fast_function\n 10.00 0.09 0.01 main\n\nEt voilà ! On voit que slow_function a pris 60 % du temps. C'est notre candidate à l'optimisation.
Exemple de code à profiler
\n\nÉcrivons un programme simple que nous allons profiler avec tous les outils :
\n\n#include <iostream>\n#include <cmath>\n\nvoid slow_function(int n) {\n volatile double sum = 0.0; // volatile pour éviter l'optimisation à zéro\n for (int i = 0; i < n; ++i) {\n for (int j = 0; j < 1000; ++j) {\n sum += std::sin(i) * std::cos(j);\n }\n }\n std::cout << sum << std::endl;\n}\n\nvoid fast_function(int n) {\n volatile int count = 0;\n for (int i = 0; i < n; ++i) {\n count += i % 2;\n }\n std::cout << count << std::endl;\n}\n\nint main() {\n slow_function(10000);\n fast_function(50000);\n return 0;\n}\n\nCompilez avec le drapeau -pg et lancez