Quelqu'un peut-il fournir une explication rapide de haut niveau sur le fonctionnement de Valgrind ? Un exemple : comment sait-il quand la mémoire est allouée et libérée ?
Réponses
Trop de publicités?Valgrind fait tourner votre application dans un "bac à sable". Pendant qu'il fonctionne dans ce bac à sable, il est capable d'insérer ses propres instructions pour effectuer un débogage et un profilage avancés.
Du manuel :
Votre programme est ensuite exécuté sur un CPU synthétique fourni par le noyau Valgrind. Lorsque le nouveau code est exécuté pour la première fois, le noyau transmet le code à l'outil sélectionné. L'outil ajoute son propre code d'instrumentation à celui-ci et renvoie le résultat au noyau, qui coordonne l'exécution continue de ce code instrumenté.
En gros, valgrind fournit un processeur virtuel qui exécute votre application. Cependant, avant que les instructions de votre application ne soient traitées, elles sont transmises à des outils (tels que memcheck). Ces outils sont en quelque sorte des plugins, et ils sont capables de modifier votre application avant qu'elle ne soit exécutée sur le processeur.
L'avantage de cette approche est que vous n'avez pas besoin de modifier ou de relier votre programme pour l'exécuter dans valgrind. Cela ralentit l'exécution de votre programme, mais valgrind n'est pas destiné à mesurer les performances ou à fonctionner pendant l'exécution normale de votre application, donc ce n'est pas vraiment un problème.
Valgrind est un outil d'analyse binaire dynamique (DPA) qui utilise le cadre de l'instrumentation binaire dynamique (DPI) pour vérifier l'allocation de la mémoire, détecter les blocages et profiler les applications. Le cadre DPI possède son propre gestionnaire de mémoire de bas niveau, son planificateur, son gestionnaire de threads et son gestionnaire de signaux. La suite d'outils Valgrind comprend des outils tels que
- Memcheck - suit l'allocation de la mémoire de manière dynamique et signale les fuites de mémoire.
- Helgrind - détecte et signale les verrous morts, les courses de données potentielles et les inversions de verrou.
- Cachegrind - simule la façon dont l'application interagit avec le cache du système et fournit des informations sur les manques de cache.
- Nulgrind - un simple valgrind qui ne fait aucune analyse. Il est utilisé par les développeurs pour évaluer les performances.
- Massif - un outil pour analyser l'utilisation de la mémoire vive de l'application.
L'outil Valgrind utilise un mécanisme de désassemblage et de resynthèse dans lequel il charge l'application dans un processus, désassemble le code de l'application, ajoute le code d'instrumentation pour l'analyse, l'assemble à nouveau et exécute l'application. Il utilise le compilateur Just Intime (JIT) pour intégrer l'application avec le code d'instrumentation.
Valgrind Tool = Valgrind Core + Tool Plugin
Valgrind Core désassemble le code de l'application et transmet le fragment de code à l'outil plugin pour l'instrumentation. Ce dernier ajoute le code d'analyse et le réassemble. Ainsi, Valgrind offre la flexibilité d'écrire notre propre outil au-dessus du cadre de Valgrind. Valgrind utilise des registres et des mémoires fictifs pour instrumenter les instructions de lecture/écriture, les appels système de lecture/écriture, les allocations de pile et de tas.
Valgrind fournit des enveloppes autour de l'appel système et enregistre des rappels pré et post pour chaque appel système afin de suivre la mémoire accédée dans le cadre de l'appel système. Valgrind est donc une couche d'abstraction entre le système d'exploitation Linux et l'application client.
Le diagramme illustre les 8 phases de Valgrind :
Vous y trouverez des informations utiles :
- Valgrind : Un cadre pour l'instrumentation binaire dynamique lourde
- http://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.wrapping
En plus de vous familiariser avec LD_PRELOAD.
Valgrind se place comme une couche entre votre programme et le système d'exploitation, interceptant les appels au système d'exploitation demandant une (dé)allocation de mémoire et enregistrant ce qui est manipulé avant d'allouer réellement la mémoire et de renvoyer un équivalent. C'est essentiellement la façon dont la plupart des profileurs de code fonctionnent, mais à un niveau beaucoup plus bas (appels système au lieu d'appels de fonctions de programme).