Manuel de suivi dynamique Solaris

Groupements

DTrace stocke les résultats des fonctions de groupement dans des objets appelés groupements. Les résultats des groupements sont indexés avec un tuple d'expressions similaires à celles utilisées pour les tableaux associatifs. En D, la syntaxe d'un groupement est la suivante :

@name[ keys ] = aggfunc ( args );

name est le nom du groupement, keys est une liste d'expressions D, séparées par des virgules, aggfunc est l'une des fonctions de groupement DTrace et args est une liste d'arguments séparés par des virgules, correspondant à la fonction de groupement. Le groupement nameest un identificateur D ayant comme préfixe le caractère spécial @. Tous les groupements de vos programmes D sont des variables globales ; il n'existe pas de groupement local de clause ou de thread. Les noms de groupement sont conservés dans un espace de noms d'identificateurs séparé des autres variables globales D. N'oubliez pas que a et @a ne sont pas la même variable si vous réutilisez les noms. Le nom de groupement spécial @ peut être utilisé pour nommer un groupement anonyme avec des programmes D simples. Le compilateur D traite ce nom en tant qu'alias du nom de groupement @_.

Les fonctions de groupement DTrace sont affichées dans le tableau suivant. La plupart des fonctions de groupement ne prennent qu'un seul argument représentant la nouvelle donnée.

Tableau 9–1 Fonctions de groupement DTrace

Nom de la fonction 

Arguments 

Résultat 

count

aucun 

Nombre d'appels. 

sum

expression scalaire 

Valeur totale des expressions spécifiées. 

avg

expression scalaire 

Moyenne arithmétique des expressions spécifiées. 

min

expression scalaire 

Valeur la plus faible parmi les expressions spécifiées. 

max

expression scalaire 

Valeur la plus élevée parmi les expressions spécifiées. 

lquantize

expression scalaire, limite inférieure, limite supérieure, valeur d'étape 

Répartition linéaire des fréquences, comprises dans la plage spécifiée, des valeurs des expressions spécifiées. Incrémente la valeur dans le compartiment inférieur le plus proche de l'expression spécifiée.

quantize

expression scalaire 

Répartition des fréquences multiples de deux des valeurs des expressions spécifiées. Incrémente la valeur dans le compartiment multiple de deux inférieur le plus proche de l'expression spécifiée.

Par exemple, pour compter le nombre d'appels système write(2) dans le système, vous pouvez utiliser une chaîne informative en tant que clé ainsi que la fonction de groupement count() :

syscall::write:entry
{
	@counts["write system calls"] = count();
}

La commande dtrace affiche les résultats du groupement par défaut lorsque le processus se termine, soit en tant que résultat d'une action explicite END, soit lorsque l'utilisateur appuie sur Control-C. L'exemple de sortie suivant montre le résultat de l'exécution de cette commande, après une attente de quelques secondes et après avoir appuyé sur Control-C :


# dtrace -s writes.d
dtrace: script './writes.d' matched 1 probe
^C

  write system calls                                              179
#

Vous pouvez compter les appels système par nom de processus en utilisant la variable execname en tant que clé à un groupement :

syscall::write:entry
{
	@counts[execname] = count();
}

L'exemple de sortie suivant montre le résultat de l'exécution de cette commande, après une attente de quelques secondes et après avoir appuyé sur Control-C :


# dtrace -s writesbycmd.d
dtrace: script './writesbycmd.d' matched 1 probe
^C

  dtrace                                                            1
  cat                                                               4
  sed                                                               9
  head                                                              9
  grep                                                             14
  find                                                             15
  tail                                                             25
  mountd                                                           28
  expr                                                             72
  sh                                                              291
  tee                                                             814
  def.dir.flp                                                    1996
  make.bin                                                       2010
#

Vous pouvez également vouloir examiner de manière plus approfondie les saisies, organisées par nom exécutable et descripteur de fichier. Le descripteur de fichier est le premier argument de write(2) ; l'exemple suivant utilise donc une clé comprenant à la fois execname et arg0 :

syscall::write:entry
{
	@counts[execname, arg0] = count();
}

L'exécution de cette commande génère un tableau comprenant le nom exécutable et le descripteur de fichier, comme illustré dans l'exemple suivant :


# dtrace -s writesbycmdfd.d
dtrace: script './writesbycmdfd.d' matched 1 probe
^C

  cat                                                               1      58
  sed                                                               1      60
  grep                                                              1      89
  tee                                                               1     156
  tee                                                               3     156
  make.bin                                                          5     164
  acomp                                                             1     263
  macrogen                                                          4     286
  cg                                                                1     397
  acomp                                                             3     736
  make.bin                                                          1     880
  iropt                                                             4    1731
#

L'exemple suivant affiche le temps moyen écoulé lors de l'appel système en écriture, par nom de processus. Cet exemple utilise la fonction de groupement avg(), en spécifiant l'expression sur laquelle effectuer le calcul de la moyenne en tant qu'argument. L'exemple fait la moyenne du temps écoulé dans l'appel système :

syscall::write:entry
{
	self->ts = timestamp;
}

syscall::write:return
/self->ts/
{
	@time[execname] = avg(timestamp - self->ts);
	self->ts = 0;
}

L'exemple de sortie suivant montre le résultat de l'exécution de cette commande, après une attente de quelques secondes et après avoir appuyé sur Control-C :


# dtrace -s writetime.d
dtrace: script './writetime.d' matched 2 probes
^C

  iropt                                                         31315
  acomp                                                         37037
  make.bin                                                      63736
  tee                                                           68702
  date                                                          84020
  sh                                                            91632
  dtrace                                                       159200
  ctfmerge                                                     321560
  install                                                      343300
  mcs                                                          394400
  get                                                          413695
  ctfconvert                                                   594400
  bringover                                                   1332465
  tail                                                        1335260
#

La moyenne peut s'avérer utile, mais c'est un élément qui ne fournit pas suffisamment de détails pour comprendre la répartition des points de données. Pour mieux comprendre la répartition, utilisez la fonction de groupement quantize(), comme illustré dans l'exemple suivant :

syscall::write:entry
{
	self->ts = timestamp;
}

syscall::write:return
/self->ts/
{
	@time[execname] = quantize(timestamp - self->ts);
	self->ts = 0;
}

Étant donné que chaque ligne de sortie devient un diagramme de répartition de fréquences, ce script affiche une sortie nettement plus longue que les précédents : L'exemple suivant présente une sélection de la sortie de test :


  lint                                              
           value  ------------- Distribution ------------- count    
            8192 |                                         0        
           16384 |                                         2        
           32768 |                                         0        
           65536 |@@@@@@@@@@@@@@@@@@@                      74       
          131072 |@@@@@@@@@@@@@@@                          59       
          262144 |@@@                                      14       
          524288 |                                         0        

  acomp                                             
           value  ------------- Distribution ------------- count    
            4096 |                                         0        
            8192 |@@@@@@@@@@@@                             840      
           16384 |@@@@@@@@@@@                              750      
           32768 |@@                                       165      
           65536 |@@@@@@                                   460      
          131072 |@@@@@@                                   446      
          262144 |                                         16       
          524288 |                                         0        
         1048576 |                                         1        
         2097152 |                                         0        

  iropt                                             
           value  ------------- Distribution ------------- count    
            4096 |                                         0        
            8192 |@@@@@@@@@@@@@@@@@@@@@@@                  4149     
           16384 |@@@@@@@@@@                               1798     
           32768 |@                                        332      
           65536 |@                                        325      
          131072 |@@                                       431      
          262144 |                                         3        
          524288 |                                         2        
         1048576 |                                         1        
         2097152 |                                         0        

Vous pouvez remarquer que les lignes de la répartition de fréquences sont toujours des multiples de deux. Chaque ligne indique le compte du nombre d'éléments supérieurs ou égaux à la valeur correspondante mais inférieurs à la valeur supérieure la plus proche. Par exemple, le résultat ci-dessus montre que iropt a 4,149 écritures prenant entre 8,192 nanosecondes et 16,383 nanosecondes incluses.

La fonction quantize() permet d'obtenir un aperçu rapide des données, mais vous souhaitez peut-être observer à la place une répartition linéaire des valeurs. Pour afficher une répartition linéaire des valeurs, utilisez la fonction de groupement lquantize(). La fonction lquantize() prend trois arguments, en plus d'une expression D : une limite inférieure, une limite supérieure et une étape. Par exemple, si vous souhaitez observer la répartition des écritures par descripteur de fichier, une quantification de multiples de deux n'est pas efficace. À la place, utilisez une quantification linéaire avec une plage restreinte, comme illustré dans l'exemple suivant :

syscall::write:entry
{
	@fds[execname] = lquantize(arg0, 0, 100, 1);
}

L'exécution de ce script pendant plusieurs secondes permet d'obtenir une grande quantité d'informations. L'exemple suivant montre une sélection de sortie classique :


  mountd                                            
           value  ------------- Distribution ------------- count    
              11 |                                         0        
              12 |@                                        4        
              13 |                                         0        
              14 |@@@@@@@@@@@@@@@@@@@@@@@@@                70       
              15 |                                         0        
              16 |@@@@@@@@@@@@                             34       
              17 |                                         0        

  xemacs-20.4                                       
           value  ------------- Distribution ------------- count    
               6 |                                         0        
               7 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  521      
               8 |                                         0        
               9 |                                         1        
              10 |                                         0        

  make.bin                                          
           value  ------------- Distribution ------------- count    
               0 |                                         0        
               1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  3596     
               2 |                                         0        
               3 |                                         0        
               4 |                                         42       
               5 |                                         50       
               6 |                                         0        

  acomp                                             
           value  ------------- Distribution ------------- count    
               0 |                                         0        
               1 |@@@@@                                    1156     
               2 |                                         0        
               3 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@         6635     
               4 |@                                        297      
               5 |                                         0        

  iropt                                             
           value  ------------- Distribution ------------- count    
               2 |                                         0        
               3 |                                         299      
               4 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  20144    
               5 |                                         0        

Vous pouvez également utiliser la fonction de groupement lquantize() pour regrouper le temps écoulé depuis un certain point du passé. Cette technique permet d'observer une modification de comportement au fil du temps. L'exemple suivant affiche la modification dans le comportement de l'appel système sur une durée de vie d'un processus exécutant la commande date(1) :

syscall::exec:return,
syscall::exece:return
/execname == "date"/
{
	self->start = vtimestamp;
}

syscall:::entry
/self->start/
{
	/*
	 * We linearly quantize on the current virtual time minus our
	 * process's start time.  We divide by 1000 to yield microseconds
	 * rather than nanoseconds.  The range runs from 0 to 10 milliseconds
	 * in steps of 100 microseconds; we expect that no date(1) process
	 * will take longer than 10 milliseconds to complete.
	 */
	@a["system calls over time"] =
	    lquantize((vtimestamp - self->start) / 1000, 0, 10000, 100);
}

syscall::rexit:entry
/self->start/
{
	self->start = 0;
}

Le script précédent fournit plus de détails sur le comportement de l'appel système lorsque de nombreux processus date(1) sont exécutés. Pour voir ce résultat, exécutez sh -c 'while true; do date >/dev/null; done' dans une fenêtre, tandis que le script D s'exécute dans une autre. Le script produit un profil du comportement de l'appel système de la commande date(1) :


# dtrace -s dateprof.d
dtrace: script './dateprof.d' matched 218 probes
^C

  system calls over time
           value  ------------- Distribution ------------- count    
             < 0 |                                         0        
               0 |@@                                       20530    
             100 |@@@@@@                                   48814    
             200 |@@@                                      28119    
             300 |@                                        14646    
             400 |@@@@@                                    41237    
             500 |                                         1259     
             600 |                                         218      
             700 |                                         116      
             800 |@                                        12783    
             900 |@@@                                      28133    
            1000 |                                         7897     
            1100 |@                                        14065    
            1200 |@@@                                      27549    
            1300 |@@@                                      25715    
            1400 |@@@@                                     35011    
            1500 |@@                                       16734    
            1600 |                                         498      
            1700 |                                         256      
            1800 |                                         369      
            1900 |                                         404      
            2000 |                                         320      
            2100 |                                         555      
            2200 |                                         54       
            2300 |                                         17       
            2400 |                                         5        
            2500 |                                         1        
            2600 |                                         7        
            2700 |                                         0        

Ce résultat donne une idée approximative des différentes phases de la commande date(1) par rapport aux services requis du noyau. Pour mieux comprendre ces phases, vous souhaitez peut-être comprendre quels appels système font l'objet d'un appel et à quel moment. Si c'est le cas, vous pouvez modifier le script D pour regrouper la variable probefunc à la place d'une chaîne constante.