Valgrind

Fiche logiciel validé
  • Création ou MAJ importante : 16/02/12
  • Correction mineure : 20/12/12
Mots-clés

Valgrind : débogueur spécialisé dans la gestion de la mémoire

Description
Fonctionnalités générales

Valgrind est un émulateur de processeur qui permet d'instrumenter dynamiquement un code afin de le profiler ou de le debugger.
En particulier, Valgrind permet de tracer les erreurs liées à la mémoire : dépassement d'indice dans un tableau, doubles free, ...

Le principe est le suivant :

  • L'exécutable qu'on souhaite analyser est passé sous le contrôle de Valgrind
  • Vagrind exécute le code sur un processeur virtuel
  • Des outils de la bibliothèque Valgrind se greffent sur ce processeur virtuel
  • Le code du processeur virtuel est traduit en code CPU

Valgrind émule un processeur virtuel synthétique d'architecture Intel (i386 et x86_64). IBM Power7, IBM z390 et ARM sont en cours. Il propose un ensemble d'outils :

  • memcheck, l'outil de base
  • cachegrind (valgrind --tool=cachegrind mon_programme) : profiling du comportement vis-à-vis du cache et de la prédiction de branchement.
  • callgrind : cachegrind + informations sur le graphe d'appel. Cachegrind a été écrit par Josef Weidendorfer, intervenant lors de la formation "Méthodologie et outils d'optimisation en développement logiciel", co-organisée par le Groupe Calcul et l'IN2P3 en Février 2012
  • Massif : profiler du tas. Massif permet de comprendre quelles parties du code font le plus d'allocations dynamiques
  • Helgrind : débogueur de threads, permet de mettre en évidence des aléas liés à l'ordre d'exécution des threads
  • Drd : helgrind dédié aux threads posix 

Memcheck est l'outil de base présent dans Valgrind. Il permet d'aller plus loin qu'un simple débogueur en :

  • vérifiant tous les read/write en mémoire
  • signalant que certains pointeurs sont mal initialisés
  • indiquant les adresses mémoires utilisées par rapport à celles réellement allouées

Par exemple, le programme suivant accède à un élément au-delà de ce qui a été alloué :

#include "stdio.h"
#include "stdlib.h"
void main (void)
{
   int * tab1=(int *)malloc(3*sizeof(int));
   int tab2[3]={3,2,1};
   int toto;
   tab1[3]=123;
   tab2[3]=237;
   printf("%d \n",tab1[3]);
   printf("%d \n",tab2[3]);
}

Avec un simple débogueur comme gdb, aucune erreur ne serait remontée. Avec valgrind, on obtiendra le message suivant :

==1888== Invalid read of size 4
==1888== at 0x8048461: main (wa.c:13)
==1888== Address 0x4199034 is 0 bytes after a block of size 12 alloc'd
==1888== at 0x4024F20: malloc (vg_replace_malloc.c:236)
==1888== by 0x8048428: main (wa.c:6)

Cachegrind :
Le modèle de cache proposé par valgrind est un modèle synthétique :

  • cache d'instructions de niveau 1
  • cache de données de niveau 2
  • cache unifié données/instructions niveau 2
  • pas de cache de niveau 3
  • un prédicteur de branchements est présent dans le processeur

En exécutant un programme sous cachegrind, on obtient un fichier de sortie qui peut ensuite être post-traité. Par exemple, l'utilitaire cg_annotate permet de connaître le comportement vis-à-vis du cache fonction par fonction.
Afin d'obtenir une visualisation graphique des résultats obtenus, vous pouvez utiliser l'outil kcachegrind.

Contexte d'utilisation dans mon laboratoire/service

A l'université de Strasbourg, j'utilise Valgrind en 2ème intention pour déboguer des problèmes mémoires quand des débogueurs classiques ne me permettent pas de diagnostiquer le problème.

Au sein de nombreuses équipes d'Inria Lille - Nord Europe, l'utilisation de Valgrind a été automatisée dans le processus de tests de non-régression pour des codes développés en C, C++ ou Fortran.

Dans l'unité INRA BIA, nous utilisons aussi régulièrement valgrind en première intention pour un déboguage plus efficace. Typiquement, en cas d'erreur de segmentation, nous relançons le programme avec valgrind avant de le lancer avec le débogueur, pour obtenir plus d'informations. Également, les erreurs dues à des "double-free" sont détectées et corrigées beaucoup plus facilement avec valgrind.

Limitations, difficultés, fonctionnalités importantes non couvertes

Comme tout émulateur, une exécution sous Valgrind est au moins 10 fois plus lente qu'une exécution en direct. De ce fait, il est parfois préférable d'analyser des portions de code plutôt que le code dans son intégralité.

Environnement du logiciel
Distributions dans lesquelles ce logiciel est intégré

Debian, Ubuntu, Centos, Scientific Linux, Redhat

Environnement de développement
Environnement utilisateur
Divers (astuces, actualités, sécurité)