As ações de registro de dados abrangem as principais ações do DTrace. Cada uma dessas ações registra dados no buffer principal por padrão, mas cada ação também pode ser usada para registrar dados em buffers especulativos. Consulte o Capítulo 11Buffers e armazenamento em buffer para obter mais detalhes sobre o buffer principal. Consulte o Capítulo 13Rastreio especulativo para obter mais detalhes sobre buffers especulativos. As descrições desta seção referem-se somente ao buffer direcionado, indicando que os dados são registrados no buffer principal ou em um buffer especulativo se a ação for após uma speculate().
void trace(expression)
A ação mais básica é a trace(), que possui uma expressão de D como seu argumento e rastreia o resultado para o buffer direcionado. As seguintes instruções são exemplos de ações trace():
trace(execname); trace(curlwpsinfo->pr_pri); trace(timestamp / 1000); trace(`lbolt); trace("somehow managed to get here");
void tracemem(address, size_t nbytes)
A ação tracemem() possui uma expressão de D como seu primeiro argumento, endereço e uma constante como seu segundo argumento, nbytes. tracemem () copia a memória do endereço especificado por addr para o buffer direcionado, de acordo com o tamanho especificado por nbytes.
void printf(string format, ...)
Como trace(), a ação printf() rastreia expressões de D. Entretanto, printf() permite uma formatação de estilo printf(3C) elaborada. Como printf(3C), os parâmetros consistem em uma seqüência de formato seguida por um número variável de argumentos. Por padrão, os argumentos são rastreados para o buffer direcionado. Os argumentos depois são formatados como resultado por dtrace(1M), de acordo com a seqüência de formato especificada. Por exemplo, os dois primeiros exemplos de trace() de trace() poderiam ser combinados em uma única printf():
printf("execname is %s; priority is %d", execname, curlwpsinfo->pr_pri);
Para obter mais informações sobre printf(), consulte o Capítulo 12Formatação de saída.
void printa(aggregation) void printa(string format, aggregation)
A ação printa() permite que você exiba e formate agregações. Consulte o Capítulo 9Agregações para obter mais detalhes sobre agregações. Se um formato não for fornecido, printa() rastreará somente uma diretiva para o consumidor do DTrace de que a agregação especificada deve ser processada e exibida usando-se o formato padrão. Se um formato for fornecido, a agregação será formatada como especificado. Consulte o Capítulo 12Formatação de saída para obter uma descrição mais detalhada da seqüência de formato printa().
printa() rastreia somente uma diretiva de que a agregação deve ser processada pelo consumidor do DTrace. Ela não processa a agregação no kernel. Portanto, o tempo entre o rastreio da diretiva de printa() e o processamento real da diretiva depende dos fatores que afetam o processamento do buffer. Esses fatores incluem a taxa de agregação, a política de armazenamento em buffer e, se essa política for de alternância, a taxa na qual os buffers são alternados. Consulte o Capítulo 9Agregações e o Capítulo 11Buffers e armazenamento em buffer para obter descrições detalhadas sobre esses fatores.
void stack(int nframes) void stack(void)
A ação stack() registra um rastreio de pilha do kernel para o buffer direcionado. A pilha do kernel terá nframes de profundidade. Se nframes não for fornecida, o número de quadros de pilha registrado será o número especificado pela opção stackframes . Por exemplo:
# 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 ... |
A ação stack() é um pouco diferente de outras ações pois ela também pode ser usada como a chave para uma agregação:
# 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)
A ação ustack() registra um rastreio de pilha do usuário para o buffer direcionado. A pilha do usuário terá nframes de profundidade. Se nframes não for fornecida, o número de quadros de pilha registrado será o número especificado pela opção ustackframes. Embora ustack() possa determinar o endereço dos quadros de chamada quando o teste for acionado, os quadros de pilha não serão traduzidos em símbolos até que a ação ustack() seja processada no nível do usuário pelo consumidor do DTrace. Se strsize for especificado e diferente de zero, ustack() irá alocar a quantidade especificada de espaço de seqüência e usá-la para realizar a tradução de endereço para símbolo diretamente do kernel. Essa tradução de símbolo direta do usuário atualmente está disponível apenas para máquinas virtuais com Java, versão 1.5 e posterior. A tradução de endereço em símbolo de Java anota as pilhas de usuário que contêm quadros de Java com o nome de método e classe de Java. Se tais quadros não puderem ser traduzidos, os quadros aparecerão somente como endereços hexadecimais.
O exemplo a seguir rastreia uma pilha sem espaço de seqüência e, portanto, nenhuma tradução de endereço em símbolo de Java:
# 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 |
Observe que os quadros de pilhas de C e C++ da máquina virtual com Java são apresentados simbolicamente usando-se nomes de símbolos “corrompidos” de C++ e os quadros de pilhas de Java são apresentados somente como endereços hexadecimais. O exemplo a seguir mostra uma chamada para ustack() com um espaço de seqüência diferente de zero:
# 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 |
O exemplo de resultado acima demonstra informações simbólicas de quadro de pilhas de Java. Ainda existem alguns quadros hexadecimais nesse resultado porque algumas funções são estáticas e não possuem entradas na tabela de símbolos do aplicativo. A translação não é possível nesses quadros.
A translação de símbolo de ustack() para quadros que não sejam de Java ocorre depois que os dados da pilha são registrados. Por isso, o processo do usuário correspondente deve ser encerrado antes que a tradução de símbolo possa ser realizada, tornando a tradução do quadro de pilhas impossível. Se o processo do usuário for encerrado antes que a translação de símbolo seja realizada, o dtrace emitirá uma mensagem de aviso, seguida pelos quadros de pilhas hexadecimais, conforme mostrado no exemplo a seguir:
dtrace: failed to grab process 100941: no such process c7b834d4 c7bca85d c7bca1a4 c7bd4374 c7bc2628 8047efc |
As técnicas para atenuar esse problema são descritas no Capítulo 33Rastreio de processo do usuário.
Finalmente, como os comandos post mortem do depurador do DTrace não podem realizar a tradução do quadro, o uso de ustack() com uma política de buffer ring sempre resulta em dados ustack() não processados.
O programa em D a seguir mostra um exemplo de ustack() que deixa strsize sem especificação:
syscall::brk:entry /execname == $$1/ { @[ustack(40)] = count(); }
Para executar este exemplo para o navegador da Web Netscape, .netscape.bin em instalações padrão do Solaris, use o seguinte comando:
# 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() é um alias para ustack() que usa a opção jstackframes para o número de quadros de pilha e para o tamanho de espaço de seqüência cujo valor é especificado pela opção jstackstrsize. O padrão de jstacksize é um valor diferente de zero. Isso significa que o uso de jstack() resultará em um pilha com tradução de quadro de Java no local.