Este artigo foi traduzido por máquina.

Desempenho do .NET

Diagnóstico de desempenho dos aplicativos .NET usando o ETW

Subramanian Ramaswamy

Baixar o exemplo de código

Escrever um aplicativo gerenciado e levá-la para uma rodada — e é lento. Seu aplicativo é funcionalmente correto, mas seu desempenho é muito a desejar. Você gostaria de diagnosticar os problemas de desempenho e resolvê-los, mas seu aplicativo está sendo executado em um ambiente de produção, para que você não pode instalar profilers ou perturbá-lo. Ou seu aplicativo não pode ser usado amplamente suficiente para justificar a compra de Visual Studio Profiler para criação de perfil de CPU.

Felizmente, ETW (rastreamento de eventos do Windows) pode atenuar estes problemas. Essa tecnologia poderosa log baseia-se em muitas partes da infraestrutura do Windows e é utilizada no Microsoft.NET Framework 4 CLR para torná-lo mais simples do que nunca para perfil seu aplicativo gerenciado. ETW coleta dados de todo o sistema e perfis de todos os recursos (CPU, disco, rede e memória), tornando-se extremamente útil para a obtenção de uma visão holística. Além disso, o ecossistema ETW pode ser ajustado para é baixa sobrecarga, tornando-o adequado para diagnósticos de produção.

O objetivo deste artigo é dar uma idéia do poder do usando ETW para o perfil de seu aplicativo gerenciado. Não vai cobrir tudo — estão disponíveis para diagnóstico de que nós não olhamos para vários eventos de sistema operacional e eventos ETW de CLR. Mas você vai obter insights sobre como o desempenho e a funcionalidade do seu aplicativo gerenciado podem ser melhorado drasticamente usando o ecossistema ETW. Para você começar com o diagnóstico com base em ETW para seu código gerenciado, eu vou mostrar uma investigação de amostra usando a ferramenta ETW livremente disponível, PerfMonitor, para download de bcl.codeplex.com/releases/view/49601 .

PerfMonitor

PerfMonitor permite que você rapidamente e facilmente coletar dados de desempenho de ETW e gerar relatórios úteis. Não pretende ser um substituto para ferramentas de análise profunda, como o Visual Studio Profiler;em vez disso, ele fornece a você uma visão geral das características de desempenho de um aplicativo e permite que você execute algumas análises rápidas.

Há uma outra ferramenta para diagnóstico ETW chamado XPerf, que está disponível gratuitamente através do Kit de ferramentas de desempenho do Windows. No entanto, enquanto XPerf é ótimo para código nativo de criação de perfil no Windows, ele ainda não tem amplo suporte para criação de perfil de código gerenciado. PerfMonitor, por outro lado, apresenta o escopo e a potência de criação de perfil de código gerenciado usando ETW. PerfMonitor tem a capacidade de reunir informações simbólicas associadas.NET Framework código de tempo de execução, tornando-se valioso para.NET Framework investigações de desempenho, embora ele não oferece suporte a análise aprofundada que XPerf pode proporcionar.

PerfMonitor é uma ferramenta totalmente independente e é tudo que você precisa para iniciar criação de perfil e diagnosticar seu aplicativo gerenciado. O apenas outro requisito é que você deve estar executando, pelo menos, Windows Vista ou Windows Server 2008. PerfMonitor é uma ferramenta de linha de comando e digitando PerfMonitor.exe usersGuide da localização trará uma visão geral. Se você tiver um cliente cujo programa pretende diagnosticar sob condições operacionais — por exemplo, em um servidor de produção — tudo que você precisa fazer é copiar o arquivo sobre para que a máquina e você está pronto para iniciar a coleta de perfis. Os perfis podem ser analisados off-line, se necessário.

Quatro fatores geralmente é examinado durante qualquer investigação de desempenho: CPU, disco, memória e capacidade de expansão. A maioria das investigações começam com a CPU, o que afeta a inicialização e o tempo de execução do seu aplicativo. Análise de disco e/S é útil quando diagnosticar tempos de inicialização longos (e/s é um fator importante na inicialização a frio tempos, que é o tempo que leva para um aplicativo iniciar quando ele tem não presentes na memória, tais como após uma reinicialização), Considerando que o consumo excessivo de memória (ou vazamentos) podem fazer com que seu aplicativo a crescer mais lentamente ao longo do tempo. Escalabilidade é importante se você quiser que seu aplicativo para obter throughput proporcional ao número de processadores.

PerfMonitor ajuda-a obter um rápido instantâneo de todas estas exceto escalabilidade e também lhe fornece informações suficientes para cavar mais fundo utilizando outras ferramentas especializadas. Por exemplo, para diagnosticar problemas com o CLR.NET lixo coleção (GC) heap, o CLRProfiler é uma aposta melhor. No entanto, PerfMonitor rapidamente informa se há um problema e precisar de cavar mais profundo utilizando outras ferramentas. Em alguns casos, PerfMonitor-se destaca o problema e contém todas as informações que você precisa enfrentar um bug de desempenho, como você verá em breve. Dê uma olhada na coluna do CLR dentro para fora, "auditoria de uso de memória para.NET Applications"( msdn.microsoft.com/magazine/dd882521 ), que aborda a importância da auditoria do programa para o uso da memória e planejamento de desempenho. Estender essa filosofia, PerfMonitor rapidamente permite auditar muitos aspectos de desempenho do seu programa gerenciado, não apenas memória.

Uma investigação de amostra: CsvToXml

O programa de exemplo que eu vou diagnosticar usando ETW converte um arquivo CSV em um arquivo XML. O código-fonte, juntamente com o pacote de solução (e um arquivo CSV entrado do exemplo, data.csv), está disponível em code.msdn.microsoft.com/mag201012ETW . Para executar o programa, execute o comando CsvToXml.exe data.csv output.

Como muitos programas, CsvToXml foi rapidamente costurada juntas e o desenvolvedor nunca antecipou que seriam utilizada para grandes arquivos CSV. Quando eu comecei a usá-lo no mundo real, eu achei que era muito lenta. Demorou mais de 15 segundos para processar um arquivo de 750000! Eu sabia que havia um problema, mas sem uma ferramenta de criação de perfil, seria realmente apenas ser adivinhando a causa da lentidão. (Pode manchá-lo apenas observando a fonte?) Felizmente, o PerfMonitor pode ajudá-lo a descobrir isso.

Gerar e exibindo o rastreamento de programa

O primeiro passo é fazer uma rápida auditoria do aplicativo, executando o seguinte comando em uma janela de prompt de comando do administrador (ETW coleta dados de toda a máquina e, portanto, precisa de privilégios de administrador):

PerfMonitor runAnalyze CsvToXml.exe data.csv out

Isto irá iniciar o log do ETW, abrir CsvToXml.exe, esperar para CsvToXml concluir, parar o registro e, finalmente, trazer uma página de Web mostrando a análise para CsvToXml. Em uma etapa fácil, você tem uma riqueza de dados para ajudá-lo a descobrir os gargalos de desempenho no CsvToXml.

O resultado deste comando é capturado em de Figura 1. A página contém, entre outros dados, o ID do processo, a linha de comando usada e discriminar os dados de desempenho de alto nível, incluindo CPU estatísticas, GC estatísticas e just-in-time (JIT). PerfMonitor também fornece uma análise de primeiro nível sobre onde começar o diagnóstico, com links úteis para artigos informativos ou outras ferramentas.

Figure 1 Performance Analysis for CsvToXml

Análise de desempenho de Figura 1 para CsvToXml

O relatório mostra que a conversão de formato levou quase 14 segundos, dos quais 13. 6 segundos foram na CPU com uma média de utilização de 99%. Assim, o cenário foi vinculada à CPU.

O tempo total em GC e os tempos de pausa de GC são baixos, que é bom.no entanto, a taxa de alocação de GC max é 105,1 MB/seg, que é excessivo — isso merece mais investigação.

Análise de CPU

A análise detalhada de CPU fornece uma divisão de tempo de CPU, como mostrado em de Figura 2, e há três maneiras de ler dados de perfil de CPU. O modo de exibição de baixo para cima rapidamente informa quais métodos estão consumindo mais tempo de CPU e devem ser diagnosticados pela primeira vez. A vista de cima para baixo é útil para descobrir se seu código precisa de alterações arquitetônicas ou estruturais e ajuda a compreender o desempenho geral do seu programa. O modo de exibição do chamador-receptor indica a relação entre métodos — por exemplo, quais os métodos que chamam.

Figure 2 Bottom-Up Analysis of CsvToXml.exe

Figura 2 ascendente análise de CsvToXml.exe

Como outros geradores de perfis de CPU, PerfMonitor vistas dar-lhe tempo inclusive (o tempo gastado em um método específico, incluindo o tempo gastado em seu receptor) e o tempo exclusivo (o tempo gastado em um método particular excluindo chamados). Quando os tempos inclusivos e exclusivos são iguais, o trabalho é feito dentro desse método específico. PerfMonitor também fornece um gráfico de utilização da CPU que divide o uso da CPU ao longo do tempo para um método específico. Pairando sobre os cabeçalhos de coluna no relatório fornece mais detalhes sobre o que eles significam.

A maioria das investigações de desempenho iniciar com a exibição de baixo para cima, que é uma lista de métodos por tempo exclusivo (este modo de exibição é mostrado em de Figura 2). Ao selecionar o modo de exibição de baixo para cima, você pode ver que o método mscorlib System.IO.File.OpenText está usando mais CPU. Clicando nesse link exibe o modo de exibição do chamador-receptor para o método OpenText, que revela que o método de CsvToXml.CsvFile.get_ColumnNames está a invocar OpenText do programa — e get_ColumnNames está consumindo quase 10 segundos do tempo da CPU ( de Figura 3). Além disso, este método é chamado de CsvToXml.CsvFile.XmlElementForRow dentro de um loop (XmlElementForRow si é chamado do método Main).

Figura 3 chamador-receptor View para get_ColumnNames

Assim, alguma coisa parece estar errado desses métodos. Puxa o código desses métodos leva você para o problema, realçado em de Figura 4: o arquivo é aberto e analisado várias vezes dentro de um loop!

Figura 4 Método ColumnNames É chamado pelo método XmlElementForRow

public string[] ColumnNames
{
  get
  {
    using (var reader = File.OpenText(Filename))
      return Parse(reader.ReadLine());
  }
}

public string XmlElementForRow(string elementName, string[] row)
{
  string ret = "<" + elementName;
  for (int i = 0; i < row.Length; i++)
    ret += " " + ToValidXmlName(ColumnNames[i]) + "=\"" + EscapeXml(row[i]) + "\"";
  ret += "/>";
  return ret;
}

Situações semelhantes acontecem com mais freqüência do que você pensa. Quando o método foi escrito originalmente, o desenvolvedor pode ter acreditado que ia ser invocado apenas raramente (como foi o caso com ColumnNames) e, portanto, não pode ter pago demasiada atenção ao seu desempenho. No entanto, situações muitas vezes vêm ao longo mais tarde que acabam chamando o método em um loop, e o desempenho do aplicativo sofre.

Em um arquivo CSV, todas as linhas tenham o mesmo formato, portanto não há nenhum ponto de fazê-lo sempre. Você pode elevar a funcionalidade de ColumnNames para o Construtor, como em de Figura 5, deixando a propriedade para fornecer os nomes das colunas em cache. Isso garante que o arquivo é lido somente uma vez.

Figura 5 os nomes de coluna para um melhor desempenho de cache

public CsvFile(string csvFileName)
{
  Filename = csvFileName;

    using (var reader = File.OpenText(Filename))
      ColumnNames = Parse(reader.ReadLine());
        
}

public string Filename { get; private set; }

public string[] ColumnNames { get; private set;}

Após a recriação, execute o comando anterior novamente e encontrar o aplicativo muito snappier.a duração é agora apenas 2,5 segundos.

No entanto, analisar os dados com a correção, você observará que tempo de CPU é ainda dominante. Novamente de perfuração em tempo de CPU e observando a análise de baixo para cima, você pode ver que a Regex agora é o método mais caro, e que ele é chamado de EscapeXml e ToValidXmlName. Porque EscapeXml é o método mais caro (ms 330 tempo exclusivo), verifique seu código-fonte:

private static string EscapeXml(string str)
{
  str = Regex.Replace(str, "\"", "&quote;");
  str = Regex.Replace(str, "<", "&lt;");
  str = Regex.Replace(str, ">", "&gt;");
  str = Regex.Replace(str, "&", "&amp;");
  return str;
}

EscapeXml também é chamado de dentro de um loop em XmlElementForRow e, portanto, tem o potencial para ser um gargalo. As expressões regulares são um pouco de exagero para estas substituições, e usando uma seqüência de caracteres Método Replace seria mais eficiente. Então substitua EscapeXml com o seguinte:

private static string EscapeXml(string str)
{
  str = str.Replace("\"", "&quote;");
  str = str.Replace("<", "&lt;");
  str = str.Replace(">", "&gt;");
  str = str.Replace("&", "&amp;");
  return str;
}

Com essa transformação, você já reduziu o tempo global de aproximadamente dois segundos, com tempo de CPU ainda dominante. Este é um desempenho aceitável — você já melhorou a velocidade de execução quase sete vezes.

Como um exercício para o leitor, eu deixei alguns bugs de desempenho mais no programa de exemplo que pode ser identificado usando eventos ETW.

Explorando GC estatísticas

Estatísticas de PerfMonitor GC fornecem uma visão geral rápida do perfil de memória. Como você pode recordar, recomendo vivamente auditoria de uso de memória, e as informações fornecidas por meio de eventos de GC ETW fornecem um instantâneo rápido de problemas com o.Heap de GC NET. A exibição de resumo rápida diz-lhe o tamanho de heap de GC agregação, as taxas de alocação e os tempos de pausa de GC. Selecionando o link de análise de tempo de GC sobre o PerfMonitor guia de resultados mostra os detalhes de GCs, quando ocorreram, quanto tempo eles consumido e assim por diante.

A informação permite que você determina se você precisa de cavar ainda mais em quaisquer problemas de memória usando o CLRProfiler ou outros geradores de perfis de memória. O artigo "criação de perfil a.NET Heap coletado"( msdn.microsoft.com/magazine/ee309515 ) escavações em Depurando o.Heap de GC NET usando o CLRProfiler.

Para este programa específico, nenhuma das estatísticas de GC parece preocupante. A taxa de alocação é alta;uma boa regra é ter sua taxa de alocação abaixo de 10 MB/s. No entanto, tempos de pausa são muito pequenos. Alocação de alta taxas show up em tempo de CPU, que na maior parte significa que não há ganhos de CPU tinha de ser — como você descobriu. No entanto, após as correções, as taxas de alocação permanecem elevadas, e isso significa que há um monte de alocações acontecendo (você pode corrigir isso?). O tempo de pausa GC de alguns milissegundos é um testamento para o GC auto-ajustável e eficiente que a.NET Framework runtime fornece. Assim, a.NET Framework GC é automaticamente cuidar de gerenciamento de memória.

Explorando JIT estatísticas

Para melhorar o tempo de inicialização, um dos primeiros itens para investigar é o tempo necessário para compilação JIT de métodos. Se o tempo decorrido é significativo (por exemplo, na maioria das vezes usados durante a inicialização do aplicativo é consumido por compilação JIT), o aplicativo pode se beneficiar de geração de imagem nativa (NGen), que elimina o tempo de compilação JIT pré-compilar o assembly e salvando-o no disco. Ou seja, o assembly é compilado em JIT e salvo no disco, eliminando a necessidade de compilação JIT para execuções subseqüentes. Antes de ir para baixo a rota NGen, no entanto, você pode também querer considerar deferring alguns dos métodos sendo JIT compilado para um ponto mais tarde no programa assim o tempo de compilação JIT não afeta a inicialização. Para obter mais informações, consulte o artigo, "O desempenho benefícios do NGen" ( msdn.microsoft.com/magazine/cc163610 ).

O aplicativo de exemplo CsvToXml.exe não teve um arranque significativo de custos e permitindo a compilação JIT todos os métodos sempre é bom. As estatísticas de compilação JIT também dizer-lhe que o número de métodos que foram JIT compilado foi 17 (sugerindo que todos os métodos chamados foram compilado JIT), e o tempo de compilação JIT total foi de 23 ms. Nem estes é um problema de desempenho com esta aplicação, mas para aplicativos maiores onde o tempo de compilação JIT é um fator, usando NGen deve eliminar todos os problemas. Normalmente, o tempo de compilação JIT torna-se um fator quando um aplicativo é iniciado JIT Compilando centenas ou milhares de métodos. Em tais casos, NGen é a solução para eliminar os custos de compilação JIT.

Mais orientações sobre como melhorar a inicialização estão disponível em outros artigos de msdn Magazine, e os eventos ETW podem ajudar a identificar e corrigir gargalos. Vários outros eventos JIT estão disponíveis também, incluindo eventos de in-line JIT podem fornecer insights sobre por que um método não era inlined.

Eventos ETW de CLR na.NET Framework 4

A equipe do CLR escreveu um post de blog sobre rastreamento de cargas DLL e determinar se uma DLL específica precisa ser carregado durante a inicialização. O processo de determinar se uma carga DLL precisa acontecer durante a inicialização torna-se mais simples com eventos ETW. Usando eventos ETW módulo carga disponíveis na.NET Framework 4, sabemos quais módulos estão carregados e por quê. Há também eventos para módulo descarrega e assim por diante.

Há vários outros eventos na.NET Framework 4 que tornam o diagnóstico de seu aplicativo gerenciado mais simples do que nunca. Figura 6 resume esses eventos. Todos os eventos que foram acionados durante a execução podem ser despejados com o comando de runPrint PerfMonitor. A equipe do CLR também tem atropelar a equipe planeja continuar adicionando mais eventos ETW para simplificar o processo de depuração de aplicativos gerenciado no futuro libera e eventos que permitem que você anexar e desanexar ETW profiling.

Figura 6 eventos ETW na.NET Framework 4

Nome da categoria de evento Descrição
Evento ETW de informações de tempo de execução Captura informações sobre o tempo de execução, inclusive o SKU, número de versão, a forma em que foi ativado o tempo de execução, os parâmetros de linha de comando com que foi iniciado, o GUID (se aplicável) e outras informações relevantes.
Exceção lançada evento ETW Captura informações sobre exceções que são geradas.
Eventos ETW de contenção Captura informações sobre contenção de monitor bloqueios ou bloqueios nativos que usa o tempo de execução.
Thread Pool ETW eventos Captura informações sobre pools de threads de trabalho e pools de threads de I/O.
Carregador ETW eventos Captura informações sobre módulos, módulos (assemblies) e domínios de aplicativo de carga e descarga.
Eventos ETW de método. Captura informações sobre métodos CLR para resolução de símbolo.
Eventos ETW GC Captura informações referentes a GC.
JIT rastreamento ETW eventos Captura informações sobre JIT inlining e chamadas de cauda.
Interoperabilidade eventos ETW Captura informações sobre geração de stub do Microsoft intermediate Idioma (MSIL) e armazenamento em cache.
Recurso de domínio de aplicativo (ARM) ETW eventos de monitoramento Captura as informações de diagnóstico sobre o Estado de um domínio de aplicativo.
Eventos de segurança do ETW Captura informações sobre nome de alta segurança e verificação de Authenticode.
Pilha ETW evento Captura de informações que são usadas com outros eventos para gerar rastreamentos de pilha após um evento é gerado.

Você encontrará dois arquivos com o sufixo PerfMonitorOutput no diretório de execução.Estes são os arquivos de log do ETW. Você também verá arquivos com o kernel para encomendar, significando que eles contêm os eventos de sistema operacional. Os dados coletados pelos PerfMonitor são os mesmos dados que XPerf usa, assim você pode usar PerfMonitor para simplificar a coleta de dados e emissão de relatórios simples e XPerf para uma análise mais avançada dos mesmos dados. O comando merge PerfMonitor converte os arquivos ETW para um formato legível pelo XPerf.

Conclusão

Investigação de desempenho usando ETW é simples, mas poderoso. Vários livre, leve com base ETW ferramentas estão disponíveis que permitir a depuração de código gerenciado com eficiência. Eu tenho apenas desnatado a superfície dos eventos ETW que estão disponíveis na.NET Framework runtime. O meu objectivo era começar a depurar seu aplicativo gerenciado usando eventos ETW e ferramental. Download PerfMonitor e usando a documentação do MSDN de eventos ETW no CLR, juntamente com o Blog de Perf CLR, irão impulsionar suas investigações de desempenho de seus aplicativos gerenciados.

Um agradecimento especial a Vance Morrison, arquiteto de parceiro para o desempenho do CLR, sua orientação e assistência com este artigo.

Subramanian Ramaswamy é gerente de programa para o desempenho do CLR na Microsoft. Ele é Ph.d. em elétrica e engenharia informática do Instituto Georgia de tecnologia.