Guia de rastreamento dinâmico Solaris

Capítulo 34 Rastreio definido estaticamente em aplicativos do usuário

O DTrace fornece um recurso para que os desenvolvedores de aplicativo do usuário definam testes personalizados no código do aplicativo para argumentar as capacidades do provedor pid. Esses testes estáticos impõem pouca ou nenhuma sobrecarga quando desativados e são ativados dinamicamente como todos os testes do DTrace. Você pode usar os testes estáticos para descrever a semântica do aplicativo para usuários do DTrace sem expor ou requerer conhecimento de implementação dos seus aplicativos. Este capítulo descreve como definir testes estáticos nos aplicativos do usuário e como usar o DTrace para ativar esses testes nos processos do usuário.

Escolhendo os pontos de teste

O DTrace permite que os desenvolvedores incorporem pontos de teste estáticos no código do aplicativo, incluindo aplicativos completos e bibliotecas compartilhadas. Esses testes podem ser ativados sempre que o aplicativo ou a biblioteca está sendo executado, seja no desenvolvimento ou na produção. Você deve definir testes que possuem um significado semântico que já seja conhecido pela comunidade de usuários do DTrace. Por exemplo, você poderia definir os testes query-receive e query-respond em um servidor da Web que corresponda a um cliente que envia uma solicitação e o servidor da Web que responde a essa solicitação. Esses testes de exemplo são facilmente entendidos pela maioria dos usuários do DTrace e correspondem às abstrações de mais alto nível do aplicativo, em vez dos detalhes de implementação de mais baixo nível. Os usuários do DTrace usam esses testes para entender a distribuição de tempo das solicitações. Se o seu teste query-receive apresentou as seqüências de solicitação de URL como um argumento, um usuário do DTrace poderia determinar quais solicitações estavam gerando a maior parte da E/S de disco, combinando esse teste com o provedor io .

Você também deve considerar a estabilidade das abstrações que descreve ao escolher os nomes e os locais de teste. Esse teste persistirá nas versões futuras do aplicativo, mesmo se a implementação for alterada? O teste faz sentido em todas as arquiteturas de sistema ou é específico de um conjunto de instruções em particular? Este capítulo discutirá os detalhes de como estas decisões orientam as definições de rastreio estático.

Adicionando testes a um aplicativo

Os testes do DTrace em bibliotecas e executáveis são definidos em uma seção ELF no binário do aplicativo correspondente. Esta seção descreve como definir seus testes, adicioná-los ao código-fonte do seu aplicativo, e argumenta o processo de construção do seu aplicativo para incluir as definições de teste do DTrace.

Definindo provedores e testes

Você define os testes do DTrace em um arquivo-fonte .d que é, em seguida, usado durante a compilação e vinculação do seu aplicativo. Primeiro, selecione um nome apropriado no seu provedor de aplicativo do usuário. O nome do provedor que você escolher será anexado ao identificador de cada processo que esteja executando o código do seu aplicativo. Por exemplo, se você escolhesse o nome de provedor myserv para um servidor da Web que estava sendo executado como o ID de processo 1203, o nome do provedor do DTrace correspondente a este processo seria myserv1203. Em seu arquivo-fonte .d, adicione uma definição de provedor semelhante ao exemplo seguinte:

provider myserv {
	...
};			

Em seguida, adicione uma definição para cada teste e os argumentos correspondentes. O exemplo seguinte define os dois testes discutidos em Escolhendo os pontos de teste. O primeiro teste possui dois argumentos, ambos do tipo string, e o segundo teste não possui argumentos. O compilador de D converte dois sublinhados consecutivos (__) em qualquer nome de teste em um hífen (-).

provider myserv {
	probe query__receive(string, string);
	probe query__respond();
};

Você deve adicionar os atributos de estabilidade à definição do seu provedor para que os consumidores de testes entendam a probabilidade de alteração nas futuras versões do seu aplicativo. Consulte o Capítulo 39Estabilidade para obter mais informações sobre os atributos de estabilidade do DTrace. Os atributos de estabilidade são definidos como mostrado no exemplo seguinte:


Exemplo 34–1 myserv.d: testes de aplicativo definidos estaticamente

#pragma D attributes Evolving/Evolving/Common provider myserv provider
#pragma D attributes Private/Private/Unknown provider myserv module
#pragma D attributes Private/Private/Unknown provider myserv function
#pragma D attributes Evolving/Evolving/Common provider myserv name
#pragma D attributes Evolving/Evolving/Common provider myserv args

provider myserv {
	probe query__receive(string, string);
	probe query__respond();
};


Observação –

Os scripts de D que usam argumentos não inteiros dos testes adicionados pelo usuário devem usar as funções copyin() e copyinstr() para recuperar tais argumentos. Consulte o Capítulo 33Rastreio de processo do usuário para obter mais informações.


Adicionando testes ao código do aplicativo

Agora que você definiu seus testes em um arquivo .d, é necessário argumentar seu código-fonte para indicar os locais que devem disparar seus testes. Considere o exemplo seguinte de código-fonte de aplicativo em C:

void
main_look(void)
{
	...
	query = wait_for_new_query();
	process_query(query)
	...
}

Para adicionar um local de teste, acrescente uma referência à macro DTRACE_PROBE() definida em <sys/sdt.h> como mostrado no exemplo seguinte:

#include <sys/sdt.h>
...

void
main_look(void)
{
	...
	query = wait_for_new_query();
	DTRACE_PROBE2(myserv, query__receive, query->clientname, query->msg);
	process_query(query)
	...
}

O sufixo 2 no nome da macro DTRACE_PROBE2 se refere ao número de argumentos que são passados para o teste. Os dois primeiros argumentos para a macro do teste são o nome do provedor e o nome do teste e devem corresponder ao seu provedor e definições de teste de D. Os argumentos da macro restantes são aqueles atribuídos às variáveis arg0..9 do DTrace quando o teste é acionado. O código-fonte do seu aplicativo pode conter várias referências ao mesmo provedor e nome de teste. Se houver várias referências ao mesmo teste em seu código-fonte, qualquer uma dessas referências de macro farão com que o teste seja acionado.

Construindo aplicativos com testes

Você deve aumentar o processo de construção em seu aplicativo para incluir o provedor e as definições de teste do DTrace. Um processo de construção típico pega cada arquivo-fonte e compila-o para criar o arquivo de objeto correspondente. Os arquivos de objeto compilados são, então, vinculados para criar o binário do aplicativo finalizado, conforme mostrado no exemplo seguinte:


cc -c src1.c
cc -c src2.c
...
cc -o myserv src1.o src2.o ...

Para incluir as definições de teste do DTrace em seu aplicativo, adicione as regras Makefile apropriadas ao seu processo de construção para executar o comando dtrace, conforme mostrado no exemplo seguinte:


cc -c src1.c
cc -c src2.c
...
dtrace -G -32 -s myserv.d src1.o src2.o ...
cc -o myserv myserv.o src1.o src2.o ...

O comando dtrace mostrado acima pós-processa os arquivos de objeto gerados pelos comandos do compilador precedente e gera o arquivo de objeto myserv.o a partir de myserv.d e os outros arquivos de objeto. O opção -G do dtrace é usada para vincular o provedor e as definições de teste ao aplicativo do usuário. A opção - 32 é usada para construir binários de 32 bits. A opção - 64 é usada para construir binários de 64 bits.