Partilhar via


Descrição Geral da Criação de Perfis

Um criador de perfil é uma ferramenta que monitora a execução de outro aplicativo. Um criador de perfil CLR (Common Language Runtime) é uma biblioteca de vínculo dinâmico (DLL) que consiste em funções que recebem mensagens e enviam mensagens para o CLR usando a API de criação de perfil. A DLL do profiler é carregada pelo CLR em tempo de execução.

As ferramentas tradicionais de criação de perfil se concentram em medir a execução do aplicativo. Ou seja, medem o tempo gasto em cada função ou o uso de memória do aplicativo ao longo do tempo. A API de criação de perfil tem como alvo uma classe mais ampla de ferramentas de diagnóstico, como utilitários de cobertura de código e até mesmo auxílios avançados de depuração. Estes usos são todos de natureza diagnóstica. A API de criação de perfil não apenas mede, mas também monitora a execução de um aplicativo. Por esse motivo, a API de criação de perfil nunca deve ser usada pelo próprio aplicativo e a execução do aplicativo não deve depender (ou ser afetada por) o criador de perfil.

A criação de perfil de um aplicativo CLR requer mais suporte do que a criação de perfil de código de máquina compilado convencionalmente. Isso ocorre porque o CLR introduz conceitos como domínios de aplicativo, coleta de lixo, tratamento de exceções gerenciadas, compilação just-in-time (JIT) de código (conversão de linguagem intermediária comum, ou CIL, código em código de máquina nativo) e recursos semelhantes. Os mecanismos convencionais de criação de perfis não podem identificar ou fornecer informações úteis sobre esses recursos. A API de criação de perfil fornece essas informações ausentes de forma eficiente, com efeito mínimo no desempenho do CLR e do aplicativo perfilado.

A compilação JIT em tempo de execução oferece boas oportunidades para criação de perfis. A API de criação de perfil permite que um criador de perfil altere o fluxo de código CIL na memória para uma rotina antes que ela seja compilada em JIT. Dessa forma, o criador de perfil pode adicionar dinamicamente código de instrumentação a rotinas específicas que precisam de investigação mais profunda. Embora essa abordagem seja possível em cenários convencionais, é muito mais fácil implementá-la para o CLR usando a API de criação de perfil.

A API de criação de perfil

Normalmente, a API de criação de perfil é usada para escrever um criador de perfil de código, que é um programa que monitora a execução de um aplicativo gerenciado.

A API de criação de perfil é usada por uma DLL do criador de perfil, que é carregada no mesmo processo que o aplicativo que está sendo perfilado. A DLL do criador de perfil implementa uma interface de retorno de chamada (ICorProfilerCallback no .NET Framework versão 1.0 e 1.1, ICorProfilerCallback2 na versão 2.0 e posterior). O CLR chama os métodos nessa interface para notificar o criador de perfil de eventos no processo perfilado. O criador de perfil pode chamar de volta para o tempo de execução usando os métodos nas interfaces ICorProfilerInfo e ICorProfilerInfo2 para obter informações sobre o estado do aplicativo perfilado.

Nota

Somente a parte de coleta de dados da solução do profiler deve ser executada no mesmo processo que o aplicativo perfilado. Toda a interface do usuário e análise de dados devem ser realizadas em um processo separado.

A ilustração a seguir mostra como a DLL do criador de perfil interage com o aplicativo que está sendo perfilado e o CLR.

Captura de tela que mostra a arquitetura de criação de perfil.

As interfaces de notificação

ICorProfilerCallback e ICorProfilerCallback2 podem ser considerados interfaces de notificação. Essas interfaces consistem em métodos como ClassLoadStarted, ClassLoadFinished e JITCompilationStarted. Cada vez que o CLR carrega ou descarrega uma classe, compila uma função e assim por diante, ele chama o método correspondente na interface ou ICorProfilerCallback2 no criador de ICorProfilerCallback perfil.

Por exemplo, um criador de perfil pode medir o desempenho do código por meio de duas funções de notificação: FunctionEnter2 e FunctionLeave2. Ele apenas carimba o tempo de cada notificação, acumula resultados e gera uma lista que indica quais funções consumiram mais tempo de CPU ou relógio de parede durante a execução do aplicativo.

As interfaces de recuperação de informações

As outras interfaces principais envolvidas na criação de perfil são ICorProfilerInfo e ICorProfilerInfo2. O criador de perfil chama essas interfaces conforme necessário para obter mais informações para ajudar em sua análise. Por exemplo, sempre que o CLR chama a função FunctionEnter2 , ele fornece um identificador de função. O criador de perfil pode obter mais informações sobre essa função chamando o método ICorProfilerInfo2::GetFunctionInfo2 para descobrir a classe pai da função, seu nome e assim por diante.

Funcionalidades Suportadas

A API de criação de perfil fornece informações sobre uma variedade de eventos e ações que ocorrem no common language runtime. Você pode usar essas informações para monitorar o funcionamento interno dos processos e para analisar o desempenho do seu aplicativo .NET Framework.

A API de criação de perfil recupera informações sobre as seguintes ações e eventos que ocorrem no CLR:

  • Eventos de inicialização e desligamento do CLR.

  • Criação de eventos de desligamento e criação de domínio de aplicativo.

  • Montagem de eventos de carga e descarga.

  • Eventos de carga e descarga de módulos.

  • Criação e destruição de eventos COM vtable.

  • Compilação just-in-time (JIT) e eventos de apresentação de código.

  • Eventos de carga e descarga de classe.

  • Criação de threads e eventos de destruição.

  • Eventos de entrada e saída de funções.

  • Exceções.

  • Transições entre execução de código gerenciado e não gerenciado.

  • Transições entre diferentes contextos de tempo de execução.

  • Informações sobre suspensões de tempo de execução.

  • Informações sobre a pilha de memória de tempo de execução e a atividade de coleta de lixo.

A API de criação de perfil pode ser chamada de qualquer linguagem compatível com COM (não gerenciada).

A API é eficiente no que diz respeito ao consumo de CPU e memória. A criação de perfil não envolve alterações no aplicativo perfilado que sejam significativas o suficiente para causar resultados enganosos.

A API de criação de perfil é útil para perfis de amostragem e não amostragem. Um perfilador de amostragem inspeciona o perfil em ticks de relógio regulares, digamos, com 5 milissegundos de intervalo. Um criador de perfil sem amostragem é informado de um evento de forma síncrona com o thread que causa o evento.

Funcionalidade não suportada

A API de criação de perfil não suporta a seguinte funcionalidade:

  • Código não gerenciado, que deve ser perfilado usando métodos Win32 convencionais. No entanto, o criador de perfil CLR inclui eventos de transição para determinar os limites entre código gerenciado e não gerenciado.

  • Aplicativos automodificativos que modificam seu próprio código para fins como programação orientada a aspetos.

  • Verificação de limites, porque a API de criação de perfil não fornece essas informações. O CLR fornece suporte intrínseco para verificação de limites de todo o código gerenciado.

  • Criação de perfil remota, que não é suportada pelos seguintes motivos:

    • A criação remota de perfis estende o tempo de execução. Ao usar as interfaces de criação de perfil, você deve minimizar o tempo de execução para que os resultados da criação de perfil não sejam afetados indevidamente. Isso é especialmente verdadeiro quando o desempenho da execução está sendo monitorado. No entanto, a criação de perfil remota não é uma limitação quando as interfaces de criação de perfil são usadas para monitorar o uso de memória ou para obter informações em tempo de execução sobre quadros de pilha, objetos e assim por diante.

    • O criador de perfil de código CLR deve registrar uma ou mais interfaces de retorno de chamada com o tempo de execução no computador local no qual o aplicativo perfilado está sendo executado. Isso limita a capacidade de criar um criador de perfil de código remoto.

Threads de notificação

Na maioria dos casos, o thread que gera um evento também executa notificações. Tais notificações (por exemplo, FunctionEnter e FunctionLeave) não precisam fornecer o explícito ThreadID. Além disso, o criador de perfil pode decidir usar o armazenamento local de thread para armazenar e atualizar seus blocos de análise em vez de indexar os blocos de análise no armazenamento global, com base no ThreadID thread afetado.

Observe que esses retornos de chamada não são serializados. Os usuários devem proteger seu código criando estruturas de dados seguras para threads e bloqueando o código do criador de perfil quando necessário para impedir o acesso paralelo de vários threads. Portanto, em certos casos, você pode receber uma sequência incomum de retornos de chamada. Por exemplo, suponha que um aplicativo gerenciado está gerando dois threads que estão executando código idêntico. Nesse caso, é possível receber um evento ICorProfilerCallback::JITCompilationStarted para alguma função de um thread e um FunctionEnter retorno de chamada do outro thread antes de receber o retorno de chamada ICorProfilerCallback::JITCompilationFinished callback. Nesse caso, o usuário receberá um retorno de FunctionEnter chamada para uma função que pode ainda não ter sido totalmente compilada just-in-time (JIT).

Segurança

Uma DLL do profiler é uma DLL não gerenciada que é executada como parte do mecanismo de execução do Common Language Runtime. Como resultado, o código na DLL do profiler não está sujeito às restrições de segurança de acesso ao código gerenciado. As únicas limitações na DLL do criador de perfil são aquelas impostas pelo sistema operacional ao usuário que está executando o aplicativo perfilado.

Os autores do Profiler devem tomar as precauções apropriadas para evitar problemas relacionados à segurança. Por exemplo, durante a instalação, uma DLL do criador de perfil deve ser adicionada a uma lista de controle de acesso (ACL) para que um usuário mal-intencionado não possa modificá-la.

Combinando código gerenciado e não gerenciado em um Code Profiler

Um criador de perfil escrito incorretamente pode causar referências circulares a si mesmo, resultando em um comportamento imprevisível.

Uma revisão da API de criação de perfil CLR pode criar a impressão de que você pode escrever um criador de perfil que contenha componentes gerenciados e não gerenciados que chamam uns aos outros por meio de interoperabilidade COM ou chamadas indiretas.

Embora isso seja possível do ponto de vista do design, a API de criação de perfil não oferece suporte a componentes gerenciados. Um criador de perfil CLR deve ser completamente não gerenciado. Tentativas de combinar código gerenciado e não gerenciado em um criador de perfil CLR podem causar violações de acesso, falha de programa ou bloqueios. Os componentes gerenciados do criador de perfil dispararão eventos de volta para seus componentes não gerenciados, que posteriormente chamarão os componentes gerenciados novamente, resultando em referências circulares.

O único local onde um criador de perfil CLR pode chamar código gerenciado com segurança é no corpo de linguagem intermediária comum (CIL) de um método. A prática recomendada para modificar o corpo CIL é usar os métodos de recompilação JIT na interface ICorProfilerCallback4 .

Também é possível usar os métodos de instrumentação mais antigos para modificar o CIL. Antes que a compilação just-in-time (JIT) de uma função seja concluída, o criador de perfil pode inserir chamadas gerenciadas no corpo CIL de um método e, em seguida, compilá-lo JIT (consulte o método ICorProfilerInfo::GetILFunctionBody ). Essa técnica pode ser usada com êxito para instrumentação seletiva de código gerenciado ou para coletar estatísticas e dados de desempenho sobre o JIT.

Como alternativa, um criador de perfil de código pode inserir ganchos nativos no corpo CIL de cada função gerenciada que chama o código não gerenciado. Esta técnica pode ser usada para instrumentação e cobertura. Por exemplo, um criador de perfil de código pode inserir ganchos de instrumentação após cada bloco CIL para garantir que o bloco tenha sido executado. A modificação do corpo CIL de um método é uma operação muito delicada, e há muitos fatores que devem ser levados em consideração.

Criação de perfil de código não gerenciado

A API de criação de perfil CLR (Common Language Runtime) fornece suporte mínimo para a criação de perfil de código não gerenciado. A seguinte funcionalidade é fornecida:

  • Enumeração de cadeias de pilha. Esse recurso permite que um criador de perfil de código determine o limite entre código gerenciado e código não gerenciado.

  • Determinação se uma cadeia de pilha corresponde a código gerenciado ou código nativo.

No .NET Framework versões 1.0 e 1.1, esses métodos estão disponíveis por meio do subconjunto em processo da API de depuração CLR. Eles são definidos no arquivo CorDebug.idl.

No .NET Framework 2.0 e posterior, você pode usar o método ICorProfilerInfo2::D oStackSnapshot para essa funcionalidade.

Usando COM

Embora as interfaces de criação de perfil sejam definidas como interfaces COM, o Common Language Runtime (CLR) não inicializa COM para usar essas interfaces. O motivo é evitar ter que definir o modelo de threading usando a função CoInitialize antes que o aplicativo gerenciado tenha tido a chance de especificar seu modelo de threading desejado. Da mesma forma, o criador de perfil em si não deve chamar CoInitialize, porque ele pode escolher um modelo de threading que é incompatível com o aplicativo que está sendo perfilado e pode fazer com que o aplicativo falhe.

Pilha de Chamadas

A API de criação de perfil fornece duas maneiras de obter pilhas de chamadas: um método de instantâneo de pilha, que permite a coleta esparsa de pilhas de chamadas, e um método de pilha de sombra, que rastreia a pilha de chamadas a cada instante.

Instantâneo de pilha

Um instantâneo de pilha é um traço da pilha de um thread em um instante no tempo. A API de criação de perfil suporta o rastreamento de funções gerenciadas na pilha, mas deixa o rastreamento de funções não gerenciadas para o próprio andador de pilha do criador de perfil.

Para obter mais informações sobre como programar o criador de perfil para percorrer pilhas gerenciadas, consulte o método ICorProfilerInfo2::D oStackSnapshot neste conjunto de documentação e Profiler Stack Walking no .NET Framework 2.0: Basics and Beyond.

Pilha de sombras

Usar o método de instantâneo com muita frequência pode criar rapidamente um problema de desempenho. Se você quiser fazer rastreamentos de pilha com freqüência, seu criador de perfil deve, em vez disso, criar uma pilha de sombra usando os retornos de chamada de exceção FunctionEnter2, FunctionLeave2, FunctionTailcall2 e ICorProfilerCallback2. A pilha de sombras está sempre atual e pode ser rapidamente copiada para o armazenamento sempre que um instantâneo de pilha for necessário.

Uma pilha de sombra pode obter argumentos de função, valores de retorno e informações sobre instanciações genéricas. Esta informação só está disponível através da pilha de sombras e pode ser obtida quando o controlo é entregue a uma função. No entanto, essas informações podem não estar disponíveis posteriormente durante a execução da função.

Retornos de chamada e profundidade de pilha

Os retornos de chamada do criador de perfil podem ser emitidos em circunstâncias muito restritas à pilha, e um estouro de pilha em um retorno de chamada do criador de perfil levará a uma saída imediata do processo. Um criador de perfil deve certificar-se de usar o mínimo de pilha possível em resposta a retornos de chamada. Se o profiler for destinado ao uso contra processos robustos contra estouro de pilha, o próprio profiler também deve evitar o estouro de pilha.

Title Description
Configurando um ambiente de criação de perfil Explica como inicializar um criador de perfil, definir notificações de eventos e criar o perfil de um serviço do Windows.
Interfaces de criação de perfil Descreve as interfaces não gerenciadas que a API de criação de perfil usa.
Criação de perfil de funções estáticas globais Descreve as funções estáticas globais não gerenciadas que a API de criação de perfil usa.
Enumerações de criação de perfil Descreve as enumerações não gerenciadas que a API de criação de perfil usa.
Estruturas de criação de perfis Descreve as estruturas não gerenciadas que a API de criação de perfil usa.