Outils pour utilisateurs

Outils du site


perl:le_debugger

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Prochaine révision
Révision précédente
perl:le_debugger [2009/03/15 00:58] – créée rootperl:le_debugger [2013/03/13 11:06] (Version actuelle) root
Ligne 1: Ligne 1:
-== 1. Présentation ==+====== Le debugger ======
  
-Le debugger fait partie intégrante de Perl et est toujours distribué avec l'interpréteur. Il est implémenté majoritairement sous la forme de modules Perl (appelés ''DB::...'', sans rapport avec les bases de données!). Le debugger est également le socle du profileur (pour étudier les performances d'un programme et les optimiser).+====== 1Présentation ======
  
-=== Sans le debugger ===+Le debugger fait partie intégrante de Perl et est toujours distribué avec l'interpréteur. Il est implémenté majoritairement sous la forme de modules Perl (appelés //DB::...//, sans rapport avec les bases de données!). Le debugger est également le socle du profileur (pour étudier les performances d'un programme et les optimiser).
  
-Nous avons vu qu'il était facile d'utiliser la console et quelques ''print'' bien placés pour obtenir des traces simples et facile à lire, par ex : +===== Sans le debugger =====
- print "Liste 'bla': ".join(' - ', @bla)."\n"; +
- print "$_ => $tab{$_]\n" foreach keys %tab;+
  
-Mais ces affichages sont limités, rébarbatifs pour les tableaux, et surtout ne peuvent pas rendre compte facilement de structures imbriquées basées sur les références. On peut alors appeler à la rescousse un module '''standard''' très pratique : +Nous avons vu qu'il était facile d'utiliser la console et quelques //print// bien placés pour obtenir des traces simples et facile à lire, par ex : 
- use Data::Dumper; +<code perl> 
-  +  print "Liste 'bla': ".join(' - ', @bla)."\n"; 
- print Dumper(\@list, \%tab);+  print "$_ => $tab{$_]\n" foreach keys %tab; 
 +</code> 
 + 
 +Mais ces affichages sont limités, rébarbatifs pour les tableaux, et surtout ne peuvent pas rendre compte facilement de structures imbriquées basées sur les références. On peut alors appeler à la rescousse un module **standard** très pratique : 
 +<code perl> 
 +  use Data::Dumper; 
 +   
 +  print Dumper(\@list, \%tab); 
 +</code>
  
 Ceci affichant par exemple : Ceci affichant par exemple :
- $VAR1 = [ +  $VAR1 = [ 
-          'lundi', +  'lundi', 
-          'mardi', +  'mardi', 
-          'mercredi' +  'mercredi' 
-         ]; +  ]; 
- $VAR2 = { +  $VAR2 = { 
-          'aout' => 'chaud', +  'aout' => 'chaud', 
-          'mai' => 'bon', +  'mai' => 'bon', 
-          'janvier' => 'froid' +  'janvier' => 'froid' 
-         };+  };
  
-Notez l'utilisation des références sur des listes ou des tableaux lors de l'appel à ''Dumper'' : sans passage par référence, les structures sont ''mises à plat'' sous forme de liste et ''Dumper'' ne peut que les considérer comme des variables distinctes à afficher. Ainsi avec ''print Dumper(@list)'' on obtiendrai : +Notez l'utilisation des références sur des listes ou des tableaux lors de l'appel à //Dumper// : sans passage par référence, les structures sont //mises à plat// sous forme de liste et //Dumper// ne peut que les considérer comme des variables distinctes à afficher. Ainsi avec //print Dumper(@list)// on obtiendrai : 
- $VAR1 = 'lundi'; +<code perl> 
- $VAR2 = 'mardi'; +  $VAR1 = 'lundi'; 
- $VAR3 = 'mercredi';+  $VAR2 = 'mardi'; 
 +  $VAR3 = 'mercredi'; 
 +</code>
  
 Il reste que ces méthodes d'introspection sont limitées et demandent des modifications fréquentes du code à analyser. Il reste que ces méthodes d'introspection sont limitées et demandent des modifications fréquentes du code à analyser.
  
 +====== 2. Utilisation ======
  
-== 2Utilisation ==+Il suffit d'invoquer son programme avec l'option //-d// de l'interpréteur : 
 +  $ perl -d ./server.pl 
 +   
 +  Loading DB routines from perl5db.pl version 1.28 
 +  Editor support available. 
 +   
 +  Enter h or `h h' for help, or `man perldebug' for more help. 
 +   
 +  main::(./server.pl:14): my $port 2500; 
 +  DB<1>
  
-Il suffit d'invoquer son programme avec l'option ''-d'de l'interpréteur : +Afin de préserver votre contexte de debug (points d'arrêts, sondes, etc), vous pouvez "recharger" le debugger avec la commande **R** quand vous avez modifié votre programme et que vous voulez continuer à le debugger. Il est donc fortement conseillé d'utiliser en parallèle son éditeur de texte et sa session de debug.
- $ perl -d ./server.pl +
-  +
- Loading DB routines from perl5db.pl version 1.28 +
- Editor support available. +
-  +
- Enter h or `h h' for help, or `man perldebug' for more help. +
-  +
- main::(./server.pl:14): my $port = 2500; +
-   DB<1>+
  
-Afin de préserver votre contexte de debug (points d'arrêts, sondes, etc), vous pouvez "recharger" le debugger avec la commande '''R''' quand vous avez modifié votre programme et que vous voulez continuer à le debugger. Il est donc fortement conseillé d'utiliser en parallèle son éditeur de texte et sa session de debug.+**Note**: le debugger utilise la //complétion// partout où cela est possible (en particulier sur les noms de variables et de fonctions), n'oubliez pas d'en abuser !
  
-'''Note''': le debugger utilise la ''complétion'' partout où cela est possible (en particulier sur les noms de variables et de fonctions), n'oubliez pas d'en abuser ! +===== Flux du programme =====
- +
-=== Flux du programme ===+
  
 Le programme est normalement compilé mais son exécution reste en attente. Pour piloter l'exécution on a accès aux commandes suivantes : Le programme est normalement compilé mais son exécution reste en attente. Pour piloter l'exécution on a accès aux commandes suivantes :
  
-{| bgcolor="#f7f8ff" cellpadding="3" cellspacing="0" border="1" style="font-size: 95%; border: gray solid 1px; border-collapse: collapse;" +^ **Commande** ^ **Nom** ^ **Action**^ 
-|- bgcolor="#f3fff3"  +**s** //Single step//| instruction suivante, avec entrée dans les fonctions| 
-| '''Commande''' || '''Nom''' || '''Action''' +**n** //Next// | instruction suivante, sans entrée dans les fonctions| 
-|+**r** //Return// | continue jusqu'à la fin de la fonction courante | 
-| '''s''' || ''Single step''|| instruction suivante, avec entrée dans les fonctions +**c** (line/sub) | //Continue// | reprend l'exécution, optionnellement jusqu'à une ligne ou l'entrée d'une fonction|
-|- +
-'''n''' || ''Next'' || instruction suivante, sans entrée dans les fonctions +
-|- +
-'''r''' || ''Return'' || continue jusqu'à la fin de la fonction courante  +
-|- +
-'''c''' (line/sub) || ''Continue'' || reprend l'exécution, optionnellement jusqu'à une ligne ou l'entrée d'une fonction +
-|}+
  
-=== Points d'arrêts ===+===== Points d'arrêts =====
  
 Le debugger devient nettement plus intéressant quand il s'agit de programmer des interruptions à des endroits choisis de son programme : Le debugger devient nettement plus intéressant quand il s'agit de programmer des interruptions à des endroits choisis de son programme :
  
-{| bgcolor="#f7f8ff" cellpadding="3" cellspacing="0" border="1" style="font-size: 95%; border: gray solid 1px; border-collapse: collapse;" +^ **Commande** ^ **Nom** ^ **Action** ^ 
-|- bgcolor="#f3fff3"  +**b** (ligne/sub (cond)) | //Breakpoint// | Point d'arrêt, ligne courante ou spécifiée ou fonction, avec condition optionnelle| 
-| '''Commande''' || '''Nom''' || '''Action'''  +**B** ligne | //Delete b// | Effacer le point d'arrêt d'une ligne donnée| 
-|+**L** //List// | Liste les points d'arrêts (et sondes+actions)|
-| '''b''' (ligne/sub (cond)) || ''Breakpoint'' || Point d'arrêt, ligne courante ou spécifiée ou fonction, avec condition optionnelle +
-|- +
-'''B''' ligne || ''Delete b'' || Effacer le point d'arrêt d'une ligne donnée +
-|- +
-'''L''' || ''List'' || Liste les points d'arrêts (et sondes+actions) +
-|}+
  
-L'utilisation des points d'arrêt mérite quelques exemples. On remarque notamment que les conditions sont des expressions Perl normales (sans le ''if'' qui est sous entendu) : +L'utilisation des points d'arrêt mérite quelques exemples. On remarque notamment que les conditions sont des expressions Perl normales (sans le //if// qui est sous entendu) : 
-   DB<2> b receive_from_client +  DB<2> b receive_from_client 
-   DB<3> L +  DB<3> L 
- ./server.pl: +  ./server.pl: 
-  73:      my ($cli) = @_; +  73: my ($cli) = @_; 
-    break if (1) +  break if (1) 
-  +   
-   DB<3> b send_to_client @_[0]->{'name'} eq 'mickey' +  DB<3> b send_to_client @_[0]->{'name'} eq 'mickey' 
-   DB<4> L +  DB<4> L 
- ./server.pl: +  ./server.pl: 
-  65:      my ($cli, $msg) = @_; +  65: my ($cli, $msg) = @_; 
-    break if (@_[0]->{'name'} eq 'mickey')+  break if (@_[0]->{'name'} eq 'mickey')
  
-'''Note''': ces exemples sont basés sur le programme source:/insia/perl/bomberman/server.pl+**Note**: ces exemples sont basés sur le programme source:/insia/perl/bomberman/server.pl
  
-=== Contexte d'exécution ===+===== Contexte d'exécution =====
  
-Suivant les instructions exécutées, le debugger met à jour son '''contexte''' en se déplaçant dans le programme (dernier point d'arrêt positionné, etc). On peut obtenir des informations sur le contexte du code en train d'être analysé ou qui va être exécuté de plusieurs manières :+Suivant les instructions exécutées, le debugger met à jour son **contexte** en se déplaçant dans le programme (dernier point d'arrêt positionné, etc). On peut obtenir des informations sur le contexte du code en train d'être analysé ou qui va être exécuté de plusieurs manières :
  
-{| bgcolor="#f7f8ff" cellpadding="3" cellspacing="0" border="1" style="font-size: 95%; border: gray solid 1px; border-collapse: collapse;" +^ **Commande** ^ **Nom** ^ **Action**^ 
-|- bgcolor="#f3fff3"  +**l** (ligne) | //line// | affiche la ligne du contexte courant et quelques suivantes| 
-| '''Commande''' || '''Nom''' || '''Action''' +**v** (ligne) | //view// | affiche les lignes "autour" du contexte courant| 
-|- +**.** //home// | positionne le contexte courant sur la prochaine ligne à exécuter|
-'''l''' (ligne) || ''line'' || affiche la ligne du contexte courant et quelques suivantes +
-|- +
-'''v''' (ligne) || ''view'' || affiche les lignes "autour" du contexte courant +
-|- +
-'''.''' || ''home'' || positionne le contexte courant sur la prochaine ligne à exécuter +
-|}+
  
-On peut également à tout moment obtenir la suite d'appel de fonctions (''backtrace'') qui nous a amené dans notre contexte courant : +On peut également à tout moment obtenir la suite d'appel de fonctions (//backtrace//) qui nous a amené dans notre contexte courant : 
-   DB<2> T +  DB<2> T 
- . = main::send_to_client(ref(HASH), 'JOIN-STATUS OK Welcome...') called from file `./server.pl' line 142 +  . = main::send_to_client(ref(HASH), 'JOIN-STATUS OK Welcome...') called from file `./server.pl' line 142 
- . = main::op_join(ref(HASH), 'noname') called from file `./server.pl' line 126 +  . = main::op_join(ref(HASH), 'noname') called from file `./server.pl' line 126 
- . = main::op_client(ref(HASH)) called from file `./server.pl' line 281+  . = main::op_client(ref(HASH)) called from file `./server.pl' line 281
  
-=== Introspection ===+===== Introspection =====
  
 Ou le nom savant pour décrire la possibilité de recenser les paquets, les fonctions et les variables déclarées. Ou le nom savant pour décrire la possibilité de recenser les paquets, les fonctions et les variables déclarées.
  
-{| bgcolor="#f7f8ff" cellpadding="3" cellspacing="0" border="1" style="font-size: 95%; border: gray solid 1px; border-collapse: collapse;" +^ **Commande** ^ **Nom** ^ **Action**^ 
-|- bgcolor="#f3fff3"  +**p** ... | //print// | l'instruction //print// de Perl, avec les mêmes limitations| 
-| '''Commande''' || '''Nom''' || '''Action''' +**x** ... | //examine// | affichage automatique comparable à //Data::Dumper//
-|+**S** regex | //subs// | affiche les fonctions, recherche par expression régulière|
-| '''p''' ... || ''print'' || l'instruction ''print'' de Perl, avec les mêmes limitations +
-|- +
-'''x''' ... || ''examine'' || affichage automatique comparable à ''Data::Dumper'' +
-|- +
-'''S''' regex || ''subs'' || affiche les fonctions, recherche par expression régulière +
-|}+
  
-La fonction la plus utilise sera sans conteste '''x''' (voir les ''watches'' plus loin toutefois), et suggère les mêmes techniques que ''Data::Dumper'' concernant les références : +La fonction la plus utilise sera sans conteste **x** (voir les //watches// plus loin toutefois), et suggère les mêmes techniques que //Data::Dumper// concernant les références : 
-   DB<5> x %linfo +  DB<5> x %linfo 
-   empty array +  empty array 
-   DB<6> x \%linfo +  DB<6> x \%linfo 
-  HASH(0x8250214) +  HASH(0x8250214) 
-      empty hash+  empty hash
  
-Les noms des fonctions sont toujours préfixées par leur paquet d'origine, ceci permettant d'analyser n'importe quel emplacement d'un programme modulaire. Le programme principal est représenté par le paquet ''main'' en Perl : +Les noms des fonctions sont toujours préfixées par leur paquet d'origine, ceci permettant d'analyser n'importe quel emplacement d'un programme modulaire. Le programme principal est représenté par le paquet //main// en Perl : 
-   DB<7> S main:: +  DB<7> S main:: 
- main::BEGIN +  main::BEGIN 
- main::bomb_explode +  main::bomb_explode 
- main::check_bomb_timeout +  main::check_bomb_timeout 
- main::del_client +  main::del_client 
- main::dumpValue +  main::dumpValue 
- main::dumpvar +  main::dumpvar 
- main::is_bomb_at +  main::is_bomb_at 
- main::is_other_player_at +  main::is_other_player_at 
- [...]+  [...]
  
-=== Surveillance ===+===== Surveillance =====
  
-Pour faire l'analyse d'un programme selon une variable et ses changements d'état, positionner correctement les points d'arrêts et effectuer les affichagent qui conviennent est peu efficace. Perl peut surveiller pour nous tout changement d'état, et en particulier des conditions quelconques sur une variable quel que soit l'endroit où celle-ci est modifiée : c'est ce qu'on appelle les sondes (''watches'' en anglais).+Pour faire l'analyse d'un programme selon une variable et ses changements d'état, positionner correctement les points d'arrêts et effectuer les affichagent qui conviennent est peu efficace. Perl peut surveiller pour nous tout changement d'état, et en particulier des conditions quelconques sur une variable quel que soit l'endroit où celle-ci est modifiée : c'est ce qu'on appelle les sondes (//watches// en anglais).
  
-{| bgcolor="#f7f8ff" cellpadding="3" cellspacing="0" border="1" style="font-size: 95%; border: gray solid 1px; border-collapse: collapse;" +^ **Commande** ^ **Nom** ^ **Action** ^ 
-|- bgcolor="#f3fff3"  +**w** //watch// | pose une sonde: arrête le programme si la variable est modifiée ou l'expression est vérifiée | 
-| '''Commande''' || '''Nom''' || '''Action''' +**W** ... | //delete watch// | supprime une sonde |
-|+
-| '''w''' variable|expression || ''watch'' || pose une sonde: arrête le programme si la variable est modifiée ou l'expression est vérifiée +
-|- +
-'''W''' ... || ''delete watch'' || supprime une sonde +
-|}+
  
-La commande '''L''' permet d'afficher les sondes posées (cf. flux du programme plus haut). Exemple d'utilisation :+La commande **L** permet d'afficher les sondes posées (cf. flux du programme plus haut). Exemple d'utilisation :
   DB<30> w @clients   DB<30> w @clients
   DB<31> w @clients > 1   DB<31> w @clients > 1
-  +   
- Watchpoint 0:   @clients changed: +  Watchpoint 0: @clients changed: 
-    old value:  '' +  old value: // 
-    new value:  'HASH(0x85eaf6c)' +  new value: 'HASH(0x85eaf6c)'
- +
-== 3. Le profileur ==+
  
-L'outil de "profilage" de Perl est basé sur les mécanisme de debug (principes d'interception de code similaire) et permet d'obtenir un aperçu précis de la répartion du temps dans les différents appels de fonction. Il suffit de lancer son programme avec l'option ad hoc, et on obtient en fin d'exécution un fichier de mesures nommé ''tmon.out''. On peut analyser ce fichier avec le programme standard ''dprofpp''+====== 3. Le profileur ======
- $ perl -d:DProf ./client.pl +
- [...] +
-  +
- $ dprofpp tmon.out  +
- Total Elapsed Time 19.32377 Seconds +
-   User+System Time 6.613772 Seconds +
- Exclusive Times +
- %Time ExclSec CumulS #Calls sec/call Csec/ Name +
-  97.2   6.429  6.429    870   0.0074 0.0074  SDL::BlitSurface +
-  0.76   0.050  0.050      1   0.0500 0.0500  SDL::Init +
-  0.74   0.049  0.049    435   0.0001 0.0001  SDL::UpdateRects +
-  0.44   0.029  0.029    435   0.0001 0.0001  SDL::Delay +
-  0.29   0.019  0.068    435   0.0000 0.0002  SDL::Surface::update +
-  0.15   0.010  0.010      2   0.0050 0.0050  SDL::IMGLoad +
-  0.15   0.010  0.010        0.0033 0.0033  DynaLoader::dl_load_file +
-  0.15   0.010  0.010      5   0.0020 0.0020  SDL::Event::BEGIN +
-  0.15   0.010  0.010     13   0.0008 0.0008  Exporter::export +
-  0.15   0.010  0.010      7   0.0014 0.0014  IO::Handle::BEGIN +
-  0.15   0.010  0.020      6   0.0017 0.0033  IO::Socket::BEGIN +
-  0.14   0.009  0.009    435   0.0000 0.0000  SDL::PollEvent +
-  0.14   0.009  0.038    435   0.0000 0.0001  SDL::App::delay +
-  0.11   0.007  6.436    870   0.0000 0.0074  SDL::Surface::blit +
-  0.08   0.005  6.544    435   0.0000 0.0150  main::win_update+
  
 +L'outil de "profilage" de Perl est basé sur les mécanisme de debug (principes d'interception de code similaire) et permet d'obtenir un aperçu précis de la répartion du temps dans les différents appels de fonction. Il suffit de lancer son programme avec l'option ad hoc, et on obtient en fin d'exécution un fichier de mesures nommé //tmon.out//. On peut analyser ce fichier avec le programme standard //dprofpp// :
 +  $ perl -d:DProf ./client.pl
 +  [...]
 +  
 +  $ dprofpp tmon.out
 +  Total Elapsed Time = 19.32377 Seconds
 +  User+System Time = 6.613772 Seconds
 +  Exclusive Times
 +  %Time ExclSec CumulS #Calls sec/call Csec/c Name
 +  97.2 6.429 6.429 870 0.0074 0.0074 SDL::BlitSurface
 +  0.76 0.050 0.050 1 0.0500 0.0500 SDL::Init
 +  0.74 0.049 0.049 435 0.0001 0.0001 SDL::UpdateRects
 +  0.44 0.029 0.029 435 0.0001 0.0001 SDL::Delay
 +  0.29 0.019 0.068 435 0.0000 0.0002 SDL::Surface::update
 +  0.15 0.010 0.010 2 0.0050 0.0050 SDL::IMGLoad
 +  0.15 0.010 0.010 3 0.0033 0.0033 DynaLoader::dl_load_file
 +  0.15 0.010 0.010 5 0.0020 0.0020 SDL::Event::BEGIN
 +  0.15 0.010 0.010 13 0.0008 0.0008 Exporter::export
 +  0.15 0.010 0.010 7 0.0014 0.0014 IO::Handle::BEGIN
 +  0.15 0.010 0.020 6 0.0017 0.0033 IO::Socket::BEGIN
 +  0.14 0.009 0.009 435 0.0000 0.0000 SDL::PollEvent
 +  0.14 0.009 0.038 435 0.0000 0.0001 SDL::App::delay
 +  0.11 0.007 6.436 870 0.0000 0.0074 SDL::Surface::blit
 +  0.08 0.005 6.544 435 0.0000 0.0150 main::win_update
perl/le_debugger.1237078685.txt.gz · Dernière modification : 2009/03/15 00:58 de root