Manuel de suivi dynamique Solaris

Actions d'enregistrement de données

Les actions d'enregistrement de données constituent les actions principales de DTrace. Chacune de ces actions enregistre des données dans le tampon principal par défaut mais elles peuvent également en enregistrer dans des tampons spéculatifs. Pour de plus amples informations sur le tampon principal, reportez-vous au Chapitre11Tampons et mise en tampon. Pour de plus amples informations sur les tampons spéculatifs, reportez-vous au Chapitre13Suivi spéculatif. Les descriptions données dans cette section se rapportent uniquement au tampon spécifié. Elles indiquent si les données sont enregistrées dans le tampon principal ou dans un tampon spéculatif, si l'action fait suite à une action speculate().

trace()

void trace(expression)

L'action la plus élémentaire est l'action trace(), qui prend comme argument une expression D et procède au suivi du résultat dans le tampon spécifié. Les instructions suivantes sont des exemples d'actions trace() :

trace(execname);
trace(curlwpsinfo->pr_pri);
trace(timestamp / 1000);
trace(`lbolt);
trace("somehow managed to get here");

tracemem()

void tracemem(address, size_t nbytes)

L'action tracemem() prend comme premier argument une expression D, address, et comme second argument une constante, nbytes. tracemem() copie la mémoire à partir de l'adresse addr dans le tampon approprié en respectant la longueur nbytes.

printf()

void printf(string format, ...) 

De la même manière que l'action trace(), l'action printf() procède au suivi d'expressions D. Toutefois, printf() autorise un formatage de style printf(3C). Comme printf(3C), les paramètres se composent d'une chaîne format suivie d'un nombre variable d'arguments. Par défaut, les arguments font l'objet d'un suivi dans le tampon spécifié. Les arguments sont ensuite formatés pour la sortie dans dtrace(1M) en fonction de la chaîne de format spécifiée. Par exemple, les deux premiers exemples de trace() de la section trace() peuvent être combinés dans une seule action printf() :

printf("execname is %s; priority is %d", execname, curlwpsinfo->pr_pri);

Pour plus d'informations sur printf(), reportez-vous au Chapitre12Format de sortie.

printa()

void printa(aggregation)
void printa(string format, aggregation)

L'action printa() permet d'afficher des groupements et de les formater. Pour de plus amples informations sur les groupements, reportez-vous au Chapitre9Groupements. Si aucun format n'est fourni, printa() procède uniquement au suivi, dans le consommateur DTrace, d'une directive en vertu de laquelle le groupement spécifié doit être traité et affiché avec le format par défaut. Si aucun format n'est fourni, le groupement sera formaté tel que spécifié. Pour plus d'informations sur la chaîne de format Chapitre12Format de sortie, reportez-vous au Chapter 12, Output Formatting().

printa() effectue uniquement le suivi d'une directive en vertu de laquelle le groupement doit être traité par le consommateur DTrace. Cette action ne traite pas le groupement dans le noyau. Par conséquent, le temps écoulé entre le suivi de la directive printa() et le traitement effectif de la directive dépend des facteurs affectant le traitement du tampon. Parmi ces facteurs figurent le taux de groupement, la stratégie de mise en tampon et, en cas de sélection de la stratégie switching, la vitesse de commutation des tampons. Pour plus d'informations sur ces facteurs, reportez-vous au Chapitre9Groupements et au Chapitre11Tampons et mise en tampon.

stack()

void stack(int nframes)
void stack(void)

L'action stack() enregistre un suivi de pile de noyau dans le tampon spécifié. La pile de noyau aura une profondeur de nframes. Si nframes n'est pas fourni, le nombre de cadres de pile enregistrés correspond au nombre spécifié par l'option stackframes. Exemple :


# dtrace -n uiomove:entry'{stack()}'
  CPU     ID                    FUNCTION:NAME
    0   9153                    uiomove:entry 
                genunix`fop_write+0x1b
                namefs`nm_write+0x1d
                genunix`fop_write+0x1b
                genunix`write+0x1f7

    0   9153                    uiomove:entry 
                genunix`fop_read+0x1b
                genunix`read+0x1d4

    0   9153                    uiomove:entry 
                genunix`strread+0x394
                specfs`spec_read+0x65
                genunix`fop_read+0x1b
                genunix`read+0x1d4
   ...

L'action stack() diffère légèrement des autres actions dans la mesure où elle peut également être utilisée en tant que clé de groupement.


# dtrace -n kmem_alloc:entry'{@[stack()] = count()}'
dtrace: description 'kmem_alloc:entry' matched 1 probe
^C

                rpcmod`endpnt_get+0x47c
                rpcmod`clnt_clts_kcallit_addr+0x26f
                rpcmod`clnt_clts_kcallit+0x22
                nfs`rfscall+0x350
                nfs`rfs2call+0x60
                nfs`nfs_getattr_otw+0x9e
                nfs`nfsgetattr+0x26
                nfs`nfs_getattr+0xb8
                genunix`fop_getattr+0x18
                genunix`cstat64+0x30
                genunix`cstatat64+0x4a
                genunix`lstat64+0x1c
                  1

                genunix`vfs_rlock_wait+0xc
                genunix`lookuppnvp+0x19d
                genunix`lookuppnat+0xe7
                genunix`lookupnameat+0x87
                genunix`lookupname+0x19
                genunix`chdir+0x18
                  1

                rpcmod`endpnt_get+0x6b1
                rpcmod`clnt_clts_kcallit_addr+0x26f
                rpcmod`clnt_clts_kcallit+0x22
                nfs`rfscall+0x350
                nfs`rfs2call+0x60
                nfs`nfs_getattr_otw+0x9e
                nfs`nfsgetattr+0x26
                nfs`nfs_getattr+0xb8
                genunix`fop_getattr+0x18
                genunix`cstat64+0x30
                genunix`cstatat64+0x4a
                genunix`lstat64+0x1c
                  1
    ...

ustack()

void ustack(int nframes, int strsize)
void ustack(int nframes)
void ustack(void)

L'action ustack() enregistre une trace de pile utilisateur dans le tampon spécifié. La pile utilisateur aura une profondeur de nframes. Si nframes n'est pas fourni, le nombre de cadres de pile enregistrés correspond au nombre spécifié par l'option ustackframes. Tant que ustack() est capable de déterminer l'adresse de cadres d'appel lorsque la sonde se déclenche, les cadres de pile ne seront convertis en symbole qu'au moment où le consommateur DTrace traite l'action ustack() au niveau utilisateur. Si strsize est spécifié et que sa valeur est différente de zéro, ustack() alloue l'espace de chaîne spécifié pour effectuer une conversion d'adresse en symbole directement depuis le noyau. Cette conversion directe en symbole utilisateur est actuellement disponible uniquement sur les machines virtuelles Java 1.5 ou une version supérieure. La conversion Java d'adresse en symbole annote les piles utilisateur contenant des cadres Java avec un nom de méthode et une classe Java. Si ces cadres ne peuvent pas être convertis, ils apparaîtront uniquement en tant qu'adresses hexadécimales.

L'exemple suivant effectue le suivi d'une pile sans espace de chaîne, et donc sans conversion Java d'adresse en symbole.


# dtrace -n syscall::write:entry'/pid == $target/{ustack(50, 0); 
    exit(0)}' -c "java -version"
dtrace: description 'syscall::write:entry' matched 1 probe
java version "1.5.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta3-b58)
Java HotSpot(TM) Client VM (build 1.5.0-beta3-b58, mixed mode)
dtrace: pid 5312 has exited
CPU     ID                    FUNCTION:NAME
  0     35                      write:entry 
              libc.so.1`_write+0x15
              libjvm.so`__1cDhpiFwrite6FipkvI_I_+0xa8
              libjvm.so`JVM_Write+0x2f
              d0c5c946
              libjava.so`Java_java_io_FileOutputStream_writeBytes+0x2c
              cb007fcd
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb000152
              libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_
                          pnMmethodHandle_pnRJavaCallArguments_
                          pnGThread__v_+0x187
              libjvm.so`__1cCosUos_exception_wrapper6FpFpnJJavaValue_
                          pnMmethodHandle_pnRJavaCallArguments_
                          pnGThread__v2468_v_+0x14
              libjvm.so`__1cJJavaCallsEcall6FpnJJavaValue_nMmethodHandle_
                          pnRJavaCallArguments_pnGThread __v_+0x28
              libjvm.so`__1cRjni_invoke_static6FpnHJNIEnv__pnJJavaValue_
                          pnI_jobject_nLJNICallType_pnK_jmethodID_pnSJNI_
                          ArgumentPusher_pnGThread__v_+0x180
              libjvm.so`jni_CallStaticVoidMethod+0x10f
              java`main+0x53d

Vous remarquerez que les cadres de pile C et C++ de la machine virtuelle Java sont présentés symboliquement, en utilisant des noms symboliques “mutilés” C++ tandis que les cadres de pile Java sont présentés uniquement sous forme d'adresses hexadécimales. L'exemple suivant illustre un appel à ustack() avec un espace de chaîne dont la valeur est différente de zéro :


# dtrace -n syscall::write:entry'/pid == $target/{ustack(50, 500); exit(0)}'
      -c "java -version"
dtrace: description 'syscall::write:entry' matched 1 probe
java version "1.5.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta3-b58)
Java HotSpot(TM) Client VM (build 1.5.0-beta3-b58, mixed mode)
dtrace: pid 5308 has exited
CPU     ID                    FUNCTION:NAME
  0     35                      write:entry 
              libc.so.1`_write+0x15
              libjvm.so`__1cDhpiFwrite6FipkvI_I_+0xa8
              libjvm.so`JVM_Write+0x2f
              d0c5c946
              libjava.so`Java_java_io_FileOutputStream_writeBytes+0x2c
              java/io/FileOutputStream.writeBytes
              java/io/FileOutputStream.write
              java/io/BufferedOutputStream.flushBuffer
              java/io/BufferedOutputStream.flush
              java/io/PrintStream.write
              sun/nio/cs/StreamEncoder$CharsetSE.writeBytes
              sun/nio/cs/StreamEncoder$CharsetSE.implFlushBuffer
              sun/nio/cs/StreamEncoder.flushBuffer
              java/io/OutputStreamWriter.flushBuffer
              java/io/PrintStream.write
              java/io/PrintStream.print
              java/io/PrintStream.println
              sun/misc/Version.print
              sun/misc/Version.print
              StubRoutines (1)
              libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_
                          pnMmethodHandle_pnRJavaCallArguments_pnGThread
                          __v_+0x187
              libjvm.so`__1cCosUos_exception_wrapper6FpFpnJJavaValue_
                          pnMmethodHandle_pnRJavaCallArguments_pnGThread
                          __v2468_v_+0x14
              libjvm.so`__1cJJavaCallsEcall6FpnJJavaValue_nMmethodHandle
                          _pnRJavaCallArguments_pnGThread__v_+0x28
              libjvm.so`__1cRjni_invoke_static6FpnHJNIEnv__pnJJavaValue_pnI
                          _jobject_nLJNICallType_pnK_jmethodID_pnSJNI
                          _ArgumentPusher_pnGThread__v_+0x180
              libjvm.so`jni_CallStaticVoidMethod+0x10f
              java`main+0x53d
              8051b9a

Le résultat de l'exemple ci-dessus affiche des informations symboliques sur les cadres de pile Java. Des cadres hexadécimaux restent affichés dans cette sortie car certaines fonctions sont statiques et n'ont pas d'entrée dans le tableau des symboles d'application. La conversion est impossible pour ces cadres.

La conversion du symbole ustack() pour les cadres autres que Java se produit après l'enregistrement des données de pile. Par conséquent, le processus utilisateur correspondant risque de se terminer avant la réalisation de la conversion du symbole, rendant la conversion des cadres de pile impossible. Si le processus utilisateur se termine avant la réalisation de la conversion du symbole, dtrace émet un message d'avertissement, suivi des cadres de pile hexadécimaux, comme illustré dans l'exemple suivant :


  dtrace: failed to grab process 100941: no such process
                c7b834d4
                c7bca85d
                c7bca1a4
                c7bd4374
                c7bc2628
                8047efc

Vous trouverez davantage d'informations sur les techniques pour restreindre ce problème au Chapitre33Suivi des processus utilisateur.

Enfin, étant donné que les commandes du débogueur DTrace post-mortem ne peuvent pas exécuter la conversion des cadres, l'utilisation de ustack() avec une stratégie de tampon ring donnera des données ustack() brutes.

Le programme D suivant montre un exemple de ustack() laissant strsize non spécifié :

syscall::brk:entry
/execname == $$1/
{
	@[ustack(40)] = count();
}

Pour exécuter cet exemple destiné au navigateur Web Netscape .netscape.bin dans les installations Solaris par défaut, utilisez la commande suivante :


# dtrace -s brk.d .netscape.bin
dtrace: description 'syscall::brk:entry' matched 1 probe
^C
                libc.so.1`_brk_unlocked+0xc
                88143f6
                88146cd
                .netscape.bin`unlocked_malloc+0x3e
                .netscape.bin`unlocked_calloc+0x22
                .netscape.bin`calloc+0x26
                .netscape.bin`_IMGCB_NewPixmap+0x149
                .netscape.bin`il_size+0x2f7
                .netscape.bin`il_jpeg_write+0xde
                8440c19
                .netscape.bin`il_first_write+0x16b
                8394670
                83928e5
                .netscape.bin`NET_ProcessHTTP+0xa6
                .netscape.bin`NET_ProcessNet+0x49a
                827b323
                libXt.so.4`XtAppProcessEvent+0x38f
                .netscape.bin`fe_EventLoop+0x190
                .netscape.bin`main+0x1875
                   1

                libc.so.1`_brk_unlocked+0xc
                libc.so.1`sbrk+0x29
                88143df
                88146cd
                .netscape.bin`unlocked_malloc+0x3e
                .netscape.bin`unlocked_calloc+0x22
                .netscape.bin`calloc+0x26
                .netscape.bin`_IMGCB_NewPixmap+0x149
                .netscape.bin`il_size+0x2f7
                .netscape.bin`il_jpeg_write+0xde
                8440c19
                .netscape.bin`il_first_write+0x16b
                8394670
                83928e5
                .netscape.bin`NET_ProcessHTTP+0xa6
                .netscape.bin`NET_ProcessNet+0x49a
                827b323
                libXt.so.4`XtAppProcessEvent+0x38f
                .netscape.bin`fe_EventLoop+0x190
                .netscape.bin`main+0x1875
                  1
    ...

jstack()

void jstack(int nframes, int strsize)
void jstack(int nframes)
void jstack(void)

jstack() est un alias de ustack() qui utilise l'option jstackframes en fonction du nombre de cadres de pile et de la taille de l'espace de chaîne, jstackstrsize. Par défaut, jstacksize prend une valeur différente de zéro. Cela signifie que l'utilisation de jstack() produit une pile avec une conversion des cadres Java.