Guía de seguimiento dinámico de Solaris

Adiciones

DTrace almacena los resultados de las funciones de adición en objetos denominados adiciones. Los resultados de la adición se indexan mediante una tupla de expresiones similares a las utilizadas para las matrices asociativas. En D, la sintaxis de una adición es:

@name[ keys ] = aggfunc ( args );

donde name es el nombre de la adición, keys es una lista separada por comas de expresiones del lenguaje D, aggfunc es una de las funciones de adición de DTrace y args es una lista separada por comas de los argumentos adecuados para la función de adición. La variable de adición name es un identificador de D que incluye, al principio, el carácter especial @. Todas las adiciones con nombre de los programas D son variables globales; no existe ninguna adición local de cláusula o subproceso. Los nombres de las adiciones se mantienen en espacios de nombres de identificadores distintos de las otras variables globales de D. Recuerde que a y @a no son la misma variable si vuelve a utilizar los nombres. El nombre de adición especial @ puede utilizarse para asignar un nombre a una adición anónima en programas D sencillos. El compilador del lenguaje D considera este nombre un alias del nombre de adición @_.

Las funciones de adición de DTrace se muestran en la siguiente tabla. La mayoría de las funciones de adición utilizan un solo argumento que representa el nuevo dato.

Tabla 9–1 Funciones de adición de DTrace

Nombre de la función 

Argumentos 

Resultado 

count

ninguno 

El número de veces que se ha realizado una llamada a una función. 

sum

expresión escalable 

El valor total de las expresiones especificadas. 

avg

expresión escalable 

La media aritmética de las expresiones especificadas. 

min

expresión escalable 

El valor inferior entre las expresiones especificadas. 

max

expresión escalable 

El valor superior entre las expresiones especificadas. 

lquantize

expresión escalable, límite inferior, límite superior, valor del paso 

Una distribución de frecuencia lineal, clasificada según el tamaño en el intervalo indicado, de los valores de las expresiones especificadas. Incrementa el valor del compartimento superior, que es inferior a la expresión especificada.

quantize

expresión escalable 

Una distribución de frecuencia de potencias de dos de los valores de las expresiones especificadas. Incrementa el valor del compartimento superior de potencias de dos, que es inferior a la expresión especificada.

Por ejemplo, para realizar el recuento de las llamadas de sistema write(2) en el mismo, puede utilizar una cadena de carácter informativo como clave y la función de adición count():

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

El comando dtrace imprime de forma predeterminada los resultados de la adición cuando finaliza el proceso, ya sea como resultado de una acción END específica o cuando el usuario pulsa Control-C. La siguiente salida de ejemplo muestra el resultado de la ejecución de este comando, al esperar unos segundos y pulsar Control-C:


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

  write system calls                                              179
#

Puede realizar un recuento de las llamadas del sistema por nombres de procesos utilizando la variable execname como clave en una adición:

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

En la siguiente salida de ejemplo, se muestra el resultado de la ejecución de este comando, al esperar varios segundos y pulsar 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
#

También es posible que desee examinar más detalladamente las acciones de escritura organizadas por el nombre del archivo ejecutable y el descriptor de archivo. El descriptor del archivo es el primer argumento de write(2), por lo que, en el siguiente ejemplo, se utiliza una clave formada por execname y arg0:

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

Al ejecutar este comando, se genera una tabla con el nombre del archivo ejecutable y el descriptor de archivo, como se muestra en el siguiente ejemplo:


# 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
#

En el siguiente ejemplo, se muestra el tiempo medio que ha durado la llamada del sistema de escritura, organizado por el nombre de proceso. En este ejemplo se utiliza la función de adición avg(), especificando la expresión que permite calcular el promedio como argumento. En este ejemplo, se calcula el promedio del tiempo cronometrado que ha durado la llamada del sistema:

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

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

En la siguiente salida de ejemplo, se muestra el resultado de la ejecución de este comando, al esperar varios segundos y pulsar 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
#

El promedio puede resultar de utilidad, pero, a menudo, no ofrece suficiente información para conocer la distribución de los puntos de datos. Para conocer detalladamente la distribución, utilice la función de adición quantize(), como se muestra en el siguiente ejemplo:

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

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

Como cada línea de salida se convierte en un diagrama de distribución de frecuencia, el resultado de esta secuencia de comandos es considerablemente más largo que los anteriores. En el siguiente ejemplo, se muestra una selección de la salida de muestra:


  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        

Tenga en cuenta que las filas de la distribución de frecuencia están formadas siempre por valores de potencias de dos. Cada fila indica el recuento del número de elementos superiores o iguales al valor correspondiente, pero inferiores al valor superior de la fila siguiente. Por ejemplo, el resultado anterior muestra que iropt presentaba 4.149 operaciones de escritura que han tardado en realizarse entre 8.192 y 16.383 nanosegundos, incluidos estos dos valores.

Mientras que quantize() es útil para obtener una perspectiva rápida de los datos, es posible que desee examinar, en su lugar, una distribución entre valores lineales. Para mostrar una distribución de valores lineales, utilice la función de adición lquantize. () La función lquantize() utiliza tres argumentos, además de una expresión de D: un límite inferior, un límite superior y un paso. Por ejemplo, si desea consultar la distribución de operaciones de escritura por descriptor de archivo, no resultaría eficaz realizar una cuantificación de potencias de dos. En su lugar, utilice una cuantificación lineal con un intervalo reducido, como se muestra en el siguiente ejemplo:

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

Al ejecutar esta secuencia de comandos durante varios segundos, se obtiene como resultado una gran cantidad de información. En el siguiente ejemplo, se muestra una selección de la salida habitual:


  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        

También puede utilizar la función de adición lquantize() para realizar una adición en el tiempo a partir de un punto del pasado. Esta técnica permite supervisar un cambio en el comportamiento a lo largo del tiempo. En el ejemplo siguiente, se muestra un cambio en el comportamiento de las llamadas del sistema durante la duración de un proceso que está ejecutando el comando 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;
}

La secuencia de comandos anterior proporciona información detallada sobre el comportamiento de las llamadas del sistema cuando se ejecutan varios procesos date(1). Para ver este resultado, ejecute sh -c 'while true; do date >/dev/null; done' en una ventana, mientras ejecuta la secuencia de comandos de D en otra. Esta secuencia de comandos genera un perfil del comportamiento de las llamadas del sistema del comando 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        

Este resultado proporciona una idea general de las diferentes fases del comando date(1) en relación con los comandos necesarios del núcleo. Para conocer mejor estas fases, es posible que desee conocer las llamadas del sistema que se están realizando en cada momento. Si es así, puede cambiar la secuencia de comandos de D para realizar la adición en la variable probefunc en lugar de en una cadena constante.