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().
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");
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.
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.
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.
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 ... |
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 ... |
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.