Partilhar via


Profiler anexar e desanexar

No.NET Framework versões antes de .NET Framework versão 4, tinham de um aplicativo e seu gerador de perfil a ser carregado ao mesmo tempo. Quando um aplicativo é iniciado, o tempo de execução é determinado se o aplicativo deve ser perfilado examinando as variáveis de ambiente e configurações do registro e então carregado o criador de perfil obrigatório. O profiler então permaneceu no espaço de processo até que o aplicativo é encerrado.

Começando com o .NET Framework 4, você pode anexar um gerador de perfil para um aplicativo depois que o aplicativo já foi iniciado, o aplicativo de perfil e, em seguida, desconectar o profiler antes do aplicativo termina. Depois que o profiler é desanexado, o aplicativo continua sendo executado como fazia antes que o profiler foi anexado. Em outras palavras, nenhum rastro permanece da presença de temporário do criador de perfil no espaço de processo.

Além disso, começando com o .NET Framework 4, criação de perfil anexar e desanexar métodos e aprimoramentos relacionados da API de criação de perfil permitem que você use ferramentas baseadas em profiler como ferramentas de diagnóstico just-in-time, out-of-the-box.

Esses aprimoramentos são discutidos nas seções a seguir:

  • Anexando um gerador de perfil

    • Anexar detalhes

    • Passo a passo anexar

    • Localizando o método AttachProfiler

    • Anexando a um aplicativo de destino antes que o tempo de execução seja carregado.

    • Anexar restrições

    • Exemplo de anexo do Profiler

    • Inicializando o Profiler após anexar.

    • Concluindo o Profiler anexar

  • A desanexação de um gerador de perfil

    • Considerações de thread durante desanexar

    • Passo a passo desanexar

    • Desanexar restrições

  • Debug

Anexando um gerador de perfil

Dois processos separados são necessárias para anexar um gerador de perfil para um aplicativo em execução: o processo de disparador e o processo de destino.

  • O processo de disparador é um executável que faz com que o profiler DLL para ser carregado no espaço de um aplicativo em execução processo. O processo de disparador usa a ICLRProfiling::AttachProfiler método perguntar o common language runtime (CLR) para carregar o DLL do profiler. Quando o profiler DLL foi carregado no processo de destino, o processo de disparador pode permanecer ou sair, a critério do desenvolvedor profiler.

  • O processo de destino contém o aplicativo que você deseja que o perfil e o CLR. Após a AttachProfiler método é chamado, o profiler a DLL é carregada para este espaço de processo junto com o aplicativo de destino.

Anexar detalhes

AttachProfileranexa o profiler especificado para o processo especificado, opcionalmente, passando alguns dados para o profiler. Ele aguarda o tempo limite especificado para a anexação concluir.

Dentro do processo de destino, o procedimento para carregar um gerador de perfil em tempo de anexar é semelhante ao procedimento para carregar um gerador de perfil no momento da inicialização: O CLR CoCreates consultará o CLSID determinado, o ICorProfilerCallback3 interface e chama o ICorProfilerCallback3::InitializeForAttach método. Se essas operações bem-sucedidas dentro do tempo limite alocado, AttachProfiler retorna um S_OK HRESULT. Portanto, o processo de disparador deve escolher um tempo limite que é suficiente para concluir a inicialização o profiler.

Observação

Tempos limite pode ocorrer porque um finalizador no processo de destino ficou maior do que o valor de tempo limite, resultando em um HRESULT_FROM_WIN32 (ERROR_TIMEOUT).Se você receber esse erro, você pode repetir a operação de anexação.

Se o tempo limite expirar antes que a conexão for concluída, AttachProfiler retorna um erro HRESULT; No entanto, a anexação pode tiveram êxito. Em tais casos, existem maneiras alternativas para determinar o sucesso. Os desenvolvedores do Profiler geralmente têm um canal de comunicação personalizada entre seu processo de disparador e o aplicativo de destino. Um canal de comunicação pode ser usado para detectar uma conexão bem-sucedida. O processo de disparador também pode detectar o sucesso chamando AttachProfiler novamente e o recebimento de CORPROF_E_PROFILER_ALREADY_ACTIVE.

Além disso, o processo de destino deve ter direitos de acesso suficientes para poder carregar a DLL do profiler. Isso pode ser um problema ao conectar a serviços (por exemplo, o processo de w3wp. exe), o que podem estar executando em contas com direitos de acesso restrito, como, por exemplo, o serviço de rede. Em tais casos, alguns diretórios no sistema de arquivos podem ter restrições de segurança para impedem o acesso pelo processo de destino. Como resultado, é responsabilidade do desenvolvedor do profiler para instalar o profiler DLL em um local que permita o acesso apropriado.

Falhas são registradas no log de eventos do aplicativo.

Passo a passo anexar

  1. As chamadas de processo de disparador AttachProfiler, identificando o processo de destino e o profiler para ser anexado e, opcionalmente, passando dados a ser dada ao profiler após anexar.

  2. Dentro do processo de destino, o CLR recebe a solicitação de conexão.

  3. Dentro do processo de destino, o CLR cria o objeto do profiler e obtém o ICorProfilerCallback3 interface a partir dele.

  4. O CLR, em seguida, chama o InitializeForAttach método, passando os dados que o processo de disparador é incluído na solicitação de anexar.

  5. O profiler inicializa por si próprio, permite que os retornos de chamada precisa e retorna com êxito.

  6. Dentro do processo de disparador, AttachProfiler retorna S_OK HRESULT, indicando que o profiler foi anexado com êxito. O processo de disparador deixa de ser relevante.

  7. Criação de perfil continua a partir deste ponto, como em todas as versões anteriores.

Localizando o método AttachProfiler

Os processos de disparador podem localizar o AttachProfiler método seguindo estas etapas:

  1. Chamar o LoadLibrary método para carregar mscoree e localizar o CLRCreateInstance método.

  2. Chamar o CLRCreateInstance método com os argumentos CLSID_CLRMetaHost e IID_ICLRMetaHost, que retorna um ICLRMetaHost interface.

  3. Chamar o ICLRMetaHost::EnumerateLoadedRuntimes método para recuperar um ICLRRuntimeInfo interface para cada instância do CLR no processo.

  4. Iterar por meio de ICLRRuntimeInfo interfaces até encontra a interface desejada ao qual anexar o profiler.

  5. Chamar o ICLRRuntimeInfo::GetInterface método com um argumento IID_ICLRProfiling para obter um ICLRProfiling interface, que fornece a AttachProfiler método.

Anexando a um aplicativo de destino antes que o tempo de execução seja carregado.

Essa funcionalidade não é suportada. Se o processo de disparador tenta chamar o AttachProfiler método especificando um processo que ainda não carregou o tempo de execução, o AttachProfiler método retorna uma falha HRESULT. Se um usuário desejar ao perfil de um aplicativo no instante em que o tempo de execução é carregado, o usuário deve definir as variáveis de ambiente apropriado (ou executar um aplicativo criado pelo desenvolvedor do profiler para fazê-lo) antes de iniciar o aplicativo de destino.

Anexar restrições

Somente um subconjunto de ICorProfilerCallback e ICorProfilerInfo métodos estão disponíveis para anexar os geradores de perfis, conforme explicado nas seções a seguir.

Restrições de ICorProfilerCallback

Quando o profiler chama o ICorProfilerInfo::SetEventMask método, deve especificar somente os sinalizadores de evento que aparecem na COR_PRF_ALLOWABLE_AFTER_ATTACH enumeração. Outros retornos de chamada não estão disponíveis para anexar os geradores de perfis. Se vincular o profiler tentar especificar um sinalizador que não esteja na máscara de bits COR_PRF_ALLOWABLE_AFTER_ATTACH, ICorProfilerInfo::SetEventMask retorna um HRESULT de CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER.

Restrições de ICorProfilerInfo

Se um gerador de perfil foi carregado chamando o AttachProfiler método tenta chamar qualquer um dos seguintes restringidas ICorProfilerInfo ou ICorProfilerInfo2 métodos, que o método retornará um HRESULT de CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER.

Restrito ICorProfilerInfo métodos:

Restrito ICorProfilerInfo2 métodos:

Restrito ICorProfilerInfo3 métodos:

Exemplo de anexo do Profiler

Este exemplo assume que o processo de disparador já sabe que o identificador do processo (PID) do processo de destino, o número de milissegundos que quiser aguardar o tempo limite, o CLSID do profiler para carga e o caminho completo para o arquivo DLL do profiler. Ele também pressupõe que o desenvolvedor do profiler definiu uma estrutura chamada MyProfilerConfigData, que armazena dados de configuração para o criador de perfil e uma função chamada PopulateMyProfilerConfigData, que coloca os dados de configuração na estrutura.

HRESULT CallAttachProfiler(DWORD dwProfileeProcID, DWORD dwMillisecondsTimeout, 
GUID profilerCLSID, LPCWSTR wszProfilerPath)
{
// This can be a data type of your own choosing for sending configuration data 
// to your profiler:
    MyProfilerConfigData profConfig;
    PopulateMyProfilerConfigData(&profConfig);
    LPVOID pvClientData = (LPVOID) &profConfig;
    DWORD cbClientData = sizeof(profConfig);

    ICLRMetaHost * pMetaHost = NULL;
    IEnumUnknown * pEnum = NULL;
    IUnknown * pUnk = NULL;
    ICLRRuntimeInfo * pRuntime = NULL;
    ICLRProfiling * pProfiling = NULL;
    HRESULT hr = E_FAIL;

    hModule = LoadLibrary(L"mscoree.dll");
    if (hModule == NULL)
        goto Cleanup;

    CLRCreateInstanceFnPtr pfnCreateInterface = 
 (CLRCreateInstanceFnPtr)GetProcAddress(hModule, "CLRCreateInterface");
    if (pfnCreateInterface == NULL)
        goto Cleanup;

    hr = (*pfnCreateInterface)(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID *)&pMetaHost);
    if (FAILED(hr))
        goto Cleanup;

    hr = pMetaHost->EnumerateLoadedRuntimes(hProcess, &pEnum);
    if (FAILED(hr))
        goto Cleanup;

    while (pEnum->Next(1, &pUnk, NULL) == S_OK)
    {
        hr = pUnk->QueryInterface(IID_ICLRRuntimeInfo, (LPVOID *) &pRuntime);
        if (FAILED(hr))
        {
            pUnk->Release();
            pUnk = NULL;
            continue;
        }

        WCHAR wszVersion[30];
        DWORD cchVersion = sizeof(wszVersion)/sizeof(wszVersion[0]);
        hr = pRuntime->GetVersionString(wszVersion, &cchVersion);
        if (SUCCEEDED(hr) &&
            (cchVersion >= 3) && 
            ((wszVersion[0] == L'v') || (wszVersion[0] == L'V')) &&
            ((wszVersion[1] >= L'4') || (wszVersion[2] != L'.')))
        {

            hr = pRuntime->GetInterface(CLSID_CLRProfiling, IID_ICLRProfiling, (LPVOID *)&pProfiling);
            if (SUCCEEDED(hr))
            {
                hr = pProfiling->AttachProfiler(
                dwProfileeProcID,
                dwMillisecondsTimeout,
                profilerCLSID,
                wszProfilerPath,
                pvClientData,
                cbClientData
                );

                pProfiling->Release();
                pProfiling = NULL;
                break;
            }
        }

        pRuntime->Release();
        pRuntime = NULL;
        pUnk->Release();
        pUnk = NULL;
    }

Cleanup:
    if (pProfiling != NULL)
    {
        pProfiling->Release();
        pProfiling = NULL;
    }
    if (pRuntime != NULL)
    {
        pRuntime->Release();
        pRuntime = NULL;
    }

    if (pUnk != NULL)
    {
        pUnk->Release();
        pUnk = NULL;
    }

    if (pEnum != NULL)
    {
        pEnum->Release();
        pEnum = NULL;
    }

    if (pMetaHost != NULL)
    {
        pMetaHost->Release();
        pMetaHost = NULL;
    }

    if (hModule != NULL)
    {
        FreeLibrary(hModule);
        hModule = NULL;
    }

    return hr;      
}

Inicializando o Profiler após anexar.

Começando com o .NET Framework 4, o ICorProfilerCallback3::InitializeForAttach método é fornecido como a contraparte de anexação da ICorProfilerCallback::Initialize método. As chamadas CLR InitializeForAttach para dar o profiler uma oportunidade de inicializar o seu estado após um anexo. No retorno de chamada, o criador de perfil chama o ICorProfilerInfo::SetEventMask método para solicitar um ou mais eventos. Diferentemente de chamadas feitas durante a ICorProfilerCallback::Initialize chamadas de método, o SetEventMask método feitas a partir de InitializeForAttach só pode definir os bits de máscara de bits COR_PRF_ALLOWABLE_AFTER_ATTACH (consulte Anexar restrições).

Ao receber um código de erro de InitializeForAttach, o CLR registra a falha para o Log de eventos do aplicativo Windows, a interface de retorno de chamada do gerador de perfil de lançamentos e descarrega o profiler. AttachProfilerRetorna o mesmo código de erro que InitializeForAttach.

Concluindo o Profiler anexar

Começando com o .NET Framework 4, o ICorProfilerCallback3::ProfilerAttachComplete retorno de chamada é emitido após a InitializeForAttach método. ProfilerAttachCompleteindica que os retornos de chamada que foram solicitados pelo profiler na InitializeForAttach método ter sido ativado, e o profiler agora pode executar o ajuste nas identificações associadas sem se preocupar notificações ausente.

Por exemplo, suponha que o profiler definiu COR_PRF_MONITOR_MODULE_LOADS durante sua InitializeForAttach retorno de chamada. Quando o criador de perfil retorna de InitializeForAttach, o CLR permite que ModuleLoad retornos de chamada e problemas de ProfilerAttachComplete retorno de chamada. O profiler poderá usar o ICorProfilerInfo3::EnumModules método enumerar ModuleIDs para todos os módulos durante carregados no momento seu ProfilerAttachComplete retorno de chamada. Além disso, ModuleLoad eventos são emitidos para todos os novos módulos que são carregados durante a enumeração. Geradores de perfis terá que lidar corretamente com as duplicatas que encontrarem. Por exemplo, um módulo que é carregado no momento certo, enquanto um gerador de perfil é anexar pode resultar no ModuleID que aparece duas vezes: na enumeração retornado por ICorProfilerInfo3::EnumModules e, em um ModuleLoadFinished retorno de chamada.

A desanexação de um gerador de perfil

A solicitação de conexão deve ser iniciada fora do processo pelo processo do disparador. No entanto, a solicitação de desanexar é iniciada no processo pelo profiler DLL quando ele chama o ICorProfilerInfo3::RequestProfilerDetach método. Se o desenvolvedor do profiler desejar iniciar a solicitação de desconexão de fora de processo (por exemplo, a partir de uma interface de usuário personalizada), o desenvolvedor deve criar um mecanismo de comunicação entre processos para sinalizar o profiler DLL (executando juntamente com o aplicativo de destino) para chamar RequestProfilerDetach.

RequestProfilerDetachexecuta a parte de seu trabalho (incluindo a definição de seu estado interno para impedir o envio de eventos para o profiler DLL) sincronizadamente antes de retornar. O restante do seu trabalho é feito de forma assíncrona, após RequestProfilerDetach retorna. Este trabalho restante é executado em um segmento separado (DetachThread) e inclui a monitoração e garantindo que todos os códigos do profiler tem sido retirado as pilhas de todo o aplicativo threads. Quando RequestProfilerDetach for concluído, o profiler recebe uma chamada de retorno final (ICorProfilerCallback3::ProfilerDetachSucceeded), antes que o CLR libera a interface e o código do profiler heaps e descarrega a DLL do profiler.

Considerações de thread durante desanexar

Controle de execução pode ser transferido para um gerador de perfil de várias maneiras. No entanto, controle não deve ser passado para um gerador de perfil depois que é descarregado e o profiler e o runtime devem compartilhar a responsabilidade de garantir que esse comportamento não ocorre:

  • O runtime não sabe sobre segmentos que são criados ou seqüestrados pelo profiler que contêm, ou talvez em breve, código do gerador de perfil na pilha. Portanto, o profiler deve garantir que ele sai de todos os threads que ele criou e deve interromper todos os amostragem ou seqüestro antes de chamar ICorProfilerInfo3::RequestProfilerDetach. Há uma exceção a essa regra: O profiler pode usar um thread que ele criou para chamar ICorProfilerInfo3::RequestProfilerDetach. No entanto, este segmento deve manter sua própria referência para a DLL do profiler através do LoadLibrary e FreeLibraryAndExitThread funções (consulte a próxima seção para obter detalhes).

  • Após as chamadas do profiler RequestProfilerDetach, o runtime deve garantir que ICorProfilerCallback métodos não causam o código do gerador de perfil permanecer na pilha de quaisquer segmentos quando o tempo de execução tenta descarregar totalmente o profiler.

Passo a passo desanexar

As seguintes etapas ocorrem quando um gerador de perfil está desanexada:

  1. O profiler sai qualquer threads, ele criou e pára de amostragem e antes de chamar o seqüestro de todos os ICorProfilerInfo3::RequestProfilerDetach, com a seguinte exceção:

    Um gerador de perfil pode implementar a desanexação utilizando um dos seus próprios threads para chamar o ICorProfilerInfo3::RequestProfilerDetach método (em vez de usando um thread criados pelo CLR). Se um gerador de perfil implementa esse comportamento, é aceitável para este thread profiler existir quando o RequestProfilerDetach método é chamado (porque esse é o segmento que chama o método). No entanto, se um gerador de perfil opta por esta implementação, deve garantir o seguinte:

    • O thread que continuará a se para chamar RequestProfilerDetach deve manter sua própria referência para a DLL do profiler (chamando o LoadLibrary função em si mesmo).

    • Após as chamadas de segmento RequestProfilerDetach, imediatamente, ele deve chamar o FreeLibraryAndExitThread função para cancelar sua isenção na DLL do profiler e sair.

  2. RequestProfilerDetachDefine o estado interno do runtime para considerar o profiler como desativado. Isso impede que as chamadas futuras para o profiler através dos métodos de retorno de chamada.

  3. RequestProfilerDetachsinais DetachThread para começar a verificação de que todos os threads tiverem exibido a qualquer restantes métodos de retorno de chamada fora de suas pilhas.

  4. RequestProfilerDetachRetorna um código de status indicando se desanexar foi iniciado com êxito.

    Neste ponto, o CLR não permite a quaisquer chamadas adicionais o profiler no CLR por meio de ICorProfilerInfo, ICorProfilerInfo2 e ICorProfilerInfo3 métodos de interface. Chamadas de imediatamente falham e retornam um HRESULT de CORPROF_E_PROFILER_DETACHING.

  5. O profiler retorna, ou sai do thread. Se o criador de perfil usado um dos seus próprios threads para fazer esta chamada para RequestProfilerDetach, ele deve chamar FreeLibraryAndExitThread partir de agora esse segmento. Se o profiler chamado RequestProfilerDetach usando um thread CLR (isto é, de dentro de um retorno de chamada), o profiler retornará o controle ao CLR.

  6. Enquanto isso, DetachThread continua a verificar se todos os threads tiverem exibido a qualquer restantes métodos de retorno de chamada fora de suas pilhas.

  7. Quando DetachThread determinou que nenhum retorno de chamada permanece na pilha do segmento, ele chama o ICorProfilerCallback3::ProfilerDetachSucceeded método. O profiler deve fazer o mínimo de trabalho na ProfilerDetachSucceeded método e retornar rapidamente.

  8. DetachThreadexecuta final Release() sobre o criador de perfil ICorProfilerCallback interface.

  9. DetachThreadchamadas de FreeLibrary função de DLL do profiler.

Desanexar restrições

Desanexação não é suportada nas seguintes situações:

  • Quando o profiler define os sinalizadores de evento imutável.

  • Quando o profiler usa testes entrar/sair/tailcall (ELT).

  • Quando o profiler usa a instrumentação do Microsoft intermediate language (MSIL) (por exemplo, chamando o SetILFunctionBody método).

Tentativa de se desconectar do profiler nesses cenários, RequestProfilerDetach retorna um erro HRESULT.

Debug

Profiler anexar e desanexar funcionalidade não impedir que um aplicativo que está sendo depurado. Um aplicativo pode ter um gerador de perfil anexar e desanexar a qualquer momento durante a sessão de depuração. Por outro lado, um aplicativo que tenha um gerador de perfil anexar (e posterior desanexar) também pode ter um depurador anexar e desanexar a qualquer momento. No entanto, um aplicativo que está suspenso por um depurador não pode ser perfilado porque ele não pode responder a um gerador de perfil anexar a solicitação.

Consulte também

Conceitos

Visão geral de criação de perfil

Outros recursos

A criação de perfil (referência de API não gerenciada)

Referência de API não gerenciada