Guia de rastreamento dinâmico Solaris

Ações de registro de dados

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

trace()

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

tracemem()

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.

printf()

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.

printa()

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.

stack()

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

ustack()

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

jstack()

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.