Le profilage s'effectue en instrumentant soit le code source du programme , soit sa forme exécutable binaire, à l'aide d'un outil appelé profileur (ou profileur de code ). Les profileurs peuvent utiliser différentes techniques, telles que les méthodes événementielles, statistiques, instrumentées et de simulation.
les interruptions matérielles , l'instrumentation du code , la simulation du jeu d'instructions , les points d'entrée du système d'exploitation et les compteurs de performance .Utilisation des profileurs

Les outils d'analyse de programmes sont essentiels pour comprendre le comportement des programmes. Les architectes informatiques en ont besoin pour évaluer les performances des programmes sur de nouvelles architectures . Les développeurs de logiciels ont besoin d'outils pour analyser leurs programmes et identifier les sections critiques du code. Les concepteurs de compilateurs utilisent souvent ces outils pour évaluer les performances de leurs algorithmes d'ordonnancement d'instructions ou de prédiction de branchement .
— ATOM, PLDI
Le résultat d'un profileur peut être :
- Un résumé statistique des événements observés (un profil )
- Les informations de profil récapitulatives sont souvent affichées avec des annotations en regard des instructions du code source où les événements se produisent, de sorte que la taille des données de mesure est linéaire par rapport à la taille du code du programme.
/* ------------ source------------------------- compte */ 0001 SI X = "A" 0055 0002 ALORS FAITES-LE 0003 AJOUTER 1 À XCOUNT 0032 0004 SINON 0005 SI X = "B" 0055
- Un flux d'événements enregistrés (une trace )
- Pour les programmes séquentiels, un profil de synthèse est généralement suffisant, mais les problèmes de performance dans les programmes parallèles (attente de messages ou problèmes de synchronisation) dépendent souvent de la relation temporelle des événements, nécessitant ainsi une trace complète pour comprendre ce qui se passe.
- La taille d'une trace (complète) est linéaire par rapport à la longueur du chemin d'exécution du programme , ce qui la rend peu pratique. Une trace peut donc être initialisée à un point du programme et terminée à un autre afin de limiter les données affichées.
- Une interaction continue avec l' hyperviseur (par exemple, une surveillance continue ou périodique via un affichage à l'écran)
- Cela permet d'activer ou de désactiver le traçage à tout moment pendant l'exécution, ainsi que de consulter les indicateurs en temps réel relatifs au programme (toujours en cours d'exécution). Cela permet également de suspendre les processus asynchrones à des moments critiques afin d'examiner plus en détail leurs interactions avec d'autres processus parallèles.
Un profileur peut être appliqué à une méthode individuelle ou à l'échelle d'un module ou d'un programme, afin d'identifier les goulots d'étranglement en mettant en évidence le code long à exécuter. Un profileur peut être utilisé pour analyser le code du point de vue temporel, dans le but de l'optimiser pour gérer différentes conditions d'exécution ou différentes charges. Les résultats du profilage peuvent être intégrés à un compilateur qui propose une optimisation guidée par le profil . Ces résultats peuvent également servir à orienter la conception et l'optimisation d'un algorithme ; l' algorithme de Krauss avec caractères génériques en est un exemple. Certains systèmes de gestion des performances applicatives intègrent des profileurs qui agrègent les données de profilage pour fournir des informations sur les charges de travail transactionnelles dans les applications distribuées .
Histoire
Des outils d'analyse des performances existaient sur les plateformes IBM/360 et IBM/370 dès le début des années 1970. Ils reposaient généralement sur des interruptions de temporisateur qui enregistraient le mot d'état du programme (PSW) à intervalles réguliers afin de détecter les points chauds du code en cours d'exécution. Il s'agissait d'un des premiers exemples d' échantillonnage (voir ci-dessous). Début 1974, les simulateurs de jeu d'instructions permettaient le traçage complet et d'autres fonctionnalités de surveillance des performances.du graphe d’appels .
En 1994, Amitabh Srivastava et Alan Eustace de Digital Equipment Corporation ont publié un article décrivant ATOM (Analysis Tools with OM). La plateforme ATOM transforme un programme en son propre profileur : lors de la compilation , elle insère du code dans le programme à analyser. Ce code inséré génère des données d'analyse. Cette technique – modifier un programme pour qu'il s'analyse lui-même – est appelée « instrumentation ».
En 2004, les gprofarticles ATOM et PLDI sont apparus sur la liste des 50 articles PLDI les plus influents pour la période de 20 ans se terminant en 1999.
Types de profileurs basés sur la sortie
Profileur plat
Les profileurs plats calculent les temps d'appel moyens à partir des appels, sans ventiler les temps d'appel en fonction de l'appelé ou du contexte.
profileur de graphe d'appels
Les profileurs de graphes d'appels affichent les temps d'appel et les fréquences des fonctions, ainsi que les chaînes d'appels impliquées en fonction de l'appelé. Dans certains outils, le contexte complet n'est pas préservé .
Profileur sensible aux entrées
Les profileurs sensibles aux entrées ajoutent une dimension supplémentaire aux profileurs plats ou basés sur des graphes d'appels en reliant les mesures de performance aux caractéristiques des charges de travail d'entrée, telles que la taille ou les valeurs des données. Ils génèrent des graphiques qui caractérisent l'évolution des performances d'une application en fonction de ses entrées.
Granularité des données dans les types de profileurs
Les profileurs, qui sont eux-mêmes des programmes, analysent les programmes cibles en collectant des informations sur leur exécution. Selon la granularité de leurs données, qui dépend de leur méthode de collecte, ils sont classés en profileurs événementiels ou statistiques . Les profileurs interrompent l'exécution du programme pour collecter des informations. Ces interruptions peuvent limiter la résolution des mesures de temps, ce qui implique que les résultats doivent être interprétés avec prudence. Les profileurs de blocs de base indiquent le nombre de cycles d'horloge machine consacrés à l'exécution de chaque ligne de code, ou un temps calculé en additionnant ces temps ; les temps rapportés par bloc de base peuvent ne pas refléter la différence entre les accès réussis et les échecs de cache .
Profileurs basés sur les événements
Des profileurs événementiels sont disponibles pour les langages de programmation suivants :
- Java : l' API JVMTI (JVM Tools Interface), anciennement JVMPI (JVM Profiling Interface), fournit des points d'entrée aux profileurs, pour intercepter des événements tels que les appels, le chargement, le déchargement et l'entrée/sortie de classes et de threads.
- .NET : Il est possible de connecter un agent de profilage au CLR en tant que serveur COM via l’API de profilage . À l’instar de Java, l’environnement d’exécution fournit ensuite diverses fonctions de rappel à l’agent, permettant de détecter des événements tels que l’exécution, l’entrée et la sortie de méthodes JIT , la création d’objets, etc. Cette fonctionnalité est particulièrement puissante car l’agent de profilage peut réécrire le bytecode de l’application cible de manière arbitraire.
- Python : Le profilage Python inclut le module profile, hotshot (qui est basé sur le graphe d'appels) et l'utilisation de la fonction 'sys.setprofile' pour intercepter des événements tels que c_{call,return,exception}, python_{call,turn,exception}.
- Ruby : Ruby utilise également une interface similaire à celle de Python pour le profilage. On y trouve Flat-profiler (dans le fichier profile.rb), un module et ruby-prof (une extension C).
Profileurs statistiques
Ces profileurs fonctionnent par échantillonnage . Un profileur par échantillonnage analyse la pile d'appels du programme cible à intervalles réguliers en utilisant les interruptions du système d'exploitation . Les profils d'échantillonnage sont généralement moins précis et spécifiques numériquement, ne fournissant qu'une approximation statistique, mais permettent au programme cible de s'exécuter à une vitesse proche de sa vitesse maximale. « L'erreur réelle est généralement supérieure à une période d'échantillonnage. En fait, si une valeur est n fois la période d'échantillonnage, l'erreur attendue est égale à la racine carrée de n périodes d'échantillonnage. »
En pratique, les profileurs par échantillonnage offrent souvent une image plus précise de l'exécution du programme cible que d'autres approches, car ils sont moins intrusifs et ont donc moins d'effets secondaires (notamment sur les caches mémoire ou les pipelines de décodage d'instructions). De plus, leur faible surcharge permet de détecter des problèmes qui resteraient autrement invisibles. Ils sont également relativement insensibles à la surestimation du coût des petites routines fréquemment appelées ou des boucles « serrées ». Ils peuvent indiquer le temps relatif passé en mode utilisateur par rapport au temps passé en mode noyau interruptible, comme lors du traitement des appels système .
Malheureusement, l'exécution de code noyau pour gérer les interruptions entraîne une légère perte de cycles CPU pour le programme cible, détourne l'utilisation du cache et ne permet pas de distinguer les différentes tâches exécutées par le code noyau non interruptible (activité de l'ordre de la microseconde) de celles exécutées par le code utilisateur. Le matériel dédié offre de meilleures performances : les interfaces JTAG des processeurs ARM Cortex-M3 et de certains processeurs MIPS récents disposent d'un registre PCSAMPLE qui échantillonne le compteur de programme de manière totalement indétectable, permettant ainsi la collecte non intrusive d'un profil d'activité plat.
utilisés pour le code Java/managé, on trouve de SmartBear Software et CLR Profiler de Microsoft . Ces profileurs prennent également en charge le profilage du code natif, ainsi que Shark d' Apple Inc. OSX) , OProfile (Linux) , Intel VTune et Parallel Amplifier (qui fait partie d' Intel Parallel Studio ), et Oracle Performance Analyzer , entre autres.
Instrumentation
Cette technique consiste à ajouter des instructions au programme cible afin de collecter les informations nécessaires. Il est important de noter que l'instrumentation d'un programme peut modifier ses performances et, dans certains cas, engendrer des résultats inexacts et/ou des bogues de Heisenberg . L'effet dépendra des informations collectées, du niveau de détail temporel rapporté et de l'utilisation ou non du profilage par blocs de base en complément de l'instrumentation. Par exemple, l'ajout de code pour compter chaque appel de procédure/routine aura probablement moins d'impact que le comptage du nombre d'exécutions de chaque instruction. Certains ordinateurs disposent d'un matériel dédié à la collecte d'informations ; dans ce cas, l'impact sur le programme est minime.
L'instrumentation est essentielle pour déterminer le niveau de contrôle et la résolution temporelle disponibles pour les profileurs.
- Manuel : Effectué par le programmeur, par exemple en ajoutant des instructions pour calculer explicitement les temps d'exécution, compter simplement les événements ou les appels aux API de mesure telles que la norme Application Response Measurement .
- Niveau source automatique : instrumentation ajoutée au code source par un outil automatique selon une politique d’instrumentation.
- Langage intermédiaire : instrumentation ajoutée à l'assembleur ou aux bytecodes décompilés permettant la prise en charge de plusieurs langages sources de niveau supérieur et évitant les problèmes de réécriture de décalage binaire (non symbolique).
- Compilateur assisté
- Traduction binaire : L'outil ajoute des instruments à un exécutable compilé .
- Instrumentation à l'exécution : Le code est instrumenté juste avant son exécution. L'exécution du programme est entièrement supervisée et contrôlée par l'outil.
- Injection dynamique : plus légère que l’instrumentation dynamique. Le code est modifié à l’exécution pour effectuer des sauts vers des fonctions auxiliaires.
Instrumentation d'interprétation
- Les options de débogage de l'interpréteur permettent de collecter des indicateurs de performance à chaque exécution d'une instruction cible. Les interpréteurs de bytecode , de table de contrôle ou JIT sont trois exemples d'interpréteurs qui contrôlent généralement l'exécution du code cible de manière exhaustive, offrant ainsi des possibilités de collecte de données extrêmement complètes.
Hyperviseur/simulateur
- Hyperviseur : Les données sont collectées en exécutant le programme (généralement) non modifié sous un hyperviseur . Exemple : SIMMON
- Simulateur et hyperviseur : Données collectées de manière interactive et sélective en exécutant le programme non modifié sous un simulateur de jeu d'instructions .