Compartilhar via


Diagnosticar atrasos na interface do usuário causados pelas extensões

Quando a interface do usuário não responde, o Visual Studio examina a pilha de chamadas do thread da interface do usuário, começando com a folha e trabalhando em direção à base. Se o Visual Studio determinar que um quadro de pilha de chamadas pertence a um módulo que faz parte de uma extensão instalada e habilitada, ele mostra uma notificação.

Notificação de atraso da interface do usuário (falta de resposta)

A notificação informa ao usuário que o atraso da interface do usuário (ou seja, a falta de resposta na interface do usuário) pode ter sido o resultado do código de uma extensão. Ele também fornece ao usuário opções para desabilitar a extensão ou notificações futuras para essa extensão.

Este documento descreve como você pode diagnosticar o que em seu código de extensão está causando notificações de atraso na interface do usuário.

Observação

Não use a instância experimental do Visual Studio para diagnosticar atrasos na interface do usuário. Algumas partes da análise da pilha de chamadas necessárias para notificações de atraso da interface do usuário são desativadas ao usar a instância experimental, o que significa que as notificações de atraso da interface do usuário podem não ser mostradas.

Uma visão geral do processo de diagnóstico é a seguinte:

  1. Identifique o cenário de gatilho.
  2. Reinicie o VS com o log de atividades ativado.
  3. Inicie o rastreamento ETW.
  4. Dispare a notificação para aparecer novamente.
  5. Pare o rastreamento ETW.
  6. Examine o log de atividades para obter a ID de atraso.
  7. Analise o rastreamento ETW usando a ID de atraso da etapa 6.

Nas seções a seguir, abordaremos essas etapas com mais detalhes.

Identifique o cenário de gatilho

Para diagnosticar um atraso na interface do usuário, primeiro você precisa identificar o que (sequência de ações) faz com que o Visual Studio mostre a notificação. Isso é para que você possa acionar a notificação mais tarde com o registro ativado.

Reinicie o VS com o log de atividades ativado

O Visual Studio pode gerar um "log de atividades" que fornece informações úteis ao depurar um problema. Para ativar o log de atividades no Visual Studio, abra o Visual Studio com a opção de linha de comando /log. Depois que o Visual Studio é iniciado, o log de atividades é armazenado no seguinte local:

%APPDATA%\Microsoft\VisualStudio\<vs_instance_id>\ActivityLog.xml

Para saber mais sobre como você pode encontrar sua ID de instância do VS, consulte Ferramentas para detectar e gerenciar instâncias do Visual Studio. Usaremos esse registro de atividades posteriormente para descobrir mais informações sobre atrasos na interface do usuário e notificações relacionadas.

Iniciando o rastreamento ETW

Você pode usar o PerfView para coletar um rastreamento ETW. O PerfView fornece uma interface fácil de usar para coletar um rastreamento ETW e analisá-lo. Use o seguinte comando para coletar um rastreamento:

Perfview.exe collect C:\trace.etl /BufferSizeMB=1024 -CircularMB:2048 -Merge:true -Providers:*Microsoft-VisualStudio:@StacksEnabled=true -NoV2Rundown /kernelEvents=default+FileIOInit+ContextSwitch+Dispatcher

Isso habilita o provedor "Microsoft-VisualStudio", que é o provedor que o Visual Studio usa para eventos relacionados a notificações de atraso da interface do usuário. Ele também especifica a palavra-chave para o provedor de kernel que o PerfView pode usar para gerar a exibição Pilhas de Tempo de Thread.

Dispare a notificação para aparecer novamente

Depois que o PerfView iniciar a coleta de rastreamento, você poderá usar a sequência de ação do gatilho (da etapa 1) para que a notificação apareça novamente. Depois que a notificação for mostrada, você poderá interromper a coleta de rastreamento para que o PerfView processe e gere o arquivo de rastreamento de saída.

Pare o rastreamento ETW

Para interromper a coleta de rastreamento, basta usar o botão Parar coleta na janela PerfView. Depois de parar a coleta de rastreamento, o PerfView processará automaticamente os eventos ETW e gerará um arquivo de rastreamento de saída.

Examine o log de atividades para obter a ID de atraso

Conforme mencionado anteriormente, você pode encontrar o log de atividades em %APPDATA%\Microsoft\VisualStudio<vs_instance_id>\ActivityLog.xml. Sempre que o Visual Studio detecta um atraso na interface do usuário de extensão, ele grava um nó no log de atividades com UIDelayNotifications como a origem. Esse nó contém quatro informações sobre o atraso da interface do usuário:

  • A ID de atraso da interface do usuário, um número sequencial que identifica exclusivamente um atraso da interface do usuário em uma sessão do VS
  • A ID da sessão, que identifica exclusivamente sua sessão do Visual Studio do início ao fechamento
  • Se uma notificação foi mostrada ou não para o atraso da interface do usuário
  • A extensão que provavelmente causou o atraso na interface do usuário
<entry>
  <record>271</record>
  <time>2018/02/03 12:02:52.867</time>
  <type>Information</type>
  <source>UIDelayNotifications</source>
  <description>A UI delay (Delay ID = 0) has been detected. (Session ID=16e49d4b-26c2-4247-ad1c-488edeb185e0; Blamed extension="UIDelayR2"; Notification shown? Yes.)</description>
</entry>

Observação

Nem todos os atrasos da interface do usuário resultam em uma notificação. Portanto, você deve sempre verificar o valor de Notificação mostrada? para identificar corretamente o atraso correto da interface do usuário.

Depois de encontrar o atraso correto da interface do usuário no log de atividades, anote a ID de atraso da interface do usuário especificada no nó. Você usará a ID para procurar o evento ETW correspondente na próxima etapa.

Analisar o rastreamento ETW

Em seguida, abra o arquivo de rastreamento. Você pode fazer isso usando a mesma instância do PerfView ou iniciando uma nova instância e definindo o caminho da pasta atual no canto superior esquerdo da janela para o local do arquivo de rastreamento.

Definindo o caminho da pasta no Perfview

Em seguida, selecione o arquivo de rastreamento no painel esquerdo e abra-o escolhendo Abrir no menu de contexto ou do botão direito do mouse.

Observação

Por padrão, o PerfView gera um arquivo Zip. Quando você abre trace.zip, ele descompacta automaticamente o arquivo e abre o rastreamento. Você pode ignorar isso desmarcando a caixa Zip durante a coleta de rastreamento. No entanto, se você estiver planejando transferir e usar rastreamentos em computadores diferentes, é altamente recomendável não desmarcar a caixa Zip. Sem essa opção, os PDBs necessários para assemblies Ngen não acompanharão o rastreamento e, portanto, os símbolos de assemblies Ngen não serão resolvidos no computador de destino. (Consulte esta postagem no blog para obter mais informações sobre PDBs para assemblies Ngen).

Pode levar vários minutos para que o PerfView processe e abra o rastreamento. Depois que o rastreamento é aberto, uma lista de várias "exibições" aparece abaixo dele.

Exibição de resumo de rastreamento do PerfView

Primeiro, usaremos a exibição Eventos para obter o intervalo de tempo do atraso da interface do usuário:

  1. Abra a exibição Eventos selecionando o nó Events no rastreamento e escolhendo Abrir no menu de contexto ou clique com o botão direito do mouse.
  2. Selecione "Microsoft-VisualStudio/ExtensionUIUnresponsiveness" no painel esquerdo.
  3. Pressionar Enter

A seleção é aplicada e todos os eventos ExtensionUIUnresponsiveness são exibidos no painel direito.

Selecionando eventos na exibição Eventos

Cada linha no painel direito corresponde a um atraso da interface do usuário. O evento inclui um valor de "ID do Atraso" que deve corresponder à ID de atraso no log de atividades da etapa 6. Como ExtensionUIUnresponsiveness é disparado no final do atraso da interface do usuário, o carimbo de data/hora do evento (aproximadamente) marca a hora de término do atraso da interface do usuário. O evento também contém a duração do atraso. Podemos subtrair a duração do carimbo de data/hora final para obter o carimbo de data/hora de quando o atraso da interface do usuário começou.

Calculando o intervalo de tempo de atraso da interface do usuário

Na captura de tela anterior, por exemplo, o carimbo de data/hora do evento é 12.125.679 e a duração do atraso é 6.143.085 (ms). Assim,

  • O início do atraso é 12.125.679 - 6.143.085 = 5.982.594.
  • O intervalo de tempo de atraso da interface do usuário é de 5.982.594 a 12.125.679.

Assim que tivermos o intervalo de tempo, podemos fechar a exibição Eventos e abrir a exibição Pilhas de Tempo de Thread (com Atividades StartStop). Essa exibição é especialmente útil porque, muitas vezes, as extensões que estão bloqueando o thread da interface do usuário estão apenas aguardando outros threads ou uma operação associada a E/S. Assim, a exibição da Pilha de CPU, que é a opção ideal para a maioria dos casos, pode não capturar o tempo que o thread gasta bloqueando, pois não está usando a CPU durante esse tempo. As Pilhas de Tempo de Thread resolvem esse problema mostrando corretamente o tempo bloqueado.

Nó de Pilhas de Tempo de Thread (com Atividades StartStop) na exibição de resumo do PerfView

Ao abrir a exibição Pilhas de Tempo de Thread, escolha o processo devenv para iniciar a análise.

Exibição de Pilhas de Tempo de Thread para análise de atraso da interface do usuário

Na exibição Pilhas de Tempo de Thread, no canto superior esquerdo da página, você pode definir o intervalo de tempo para os valores que calculamos na etapa anterior e pressionar Enter para que as pilhas sejam ajustadas a esse intervalo de tempo.

Observação

Determinar qual thread é o thread da interface do usuário (inicialização) pode ser contra-intuitivo se a coleta de rastreamento for iniciada depois que o Visual Studio já estiver aberto. No entanto, os primeiros elementos na pilha do thread da interface do usuário (inicialização) provavelmente são sempre DLLs do sistema operacional (ntdll.dll e kernel32.dll) seguidos por devenv!? e então msenv!?. Essa sequência pode ajudar a identificar o thread da interface do usuário.

Identificando o thread de inicialização

Você também pode filtrar ainda mais essa exibição incluindo apenas pilhas que contêm módulos do seu pacote.

  • Defina GroupPats como texto vazio para remover qualquer agrupamento adicionado por padrão.
  • Defina IncPats para incluir parte do nome do assembly, além do filtro de processo existente. Neste caso, deve ser devenv;UIDelayR2.

Configurando GroupPath e IncPath na exibição Pilhas de Tempo de Thread

O PerfView tem orientação detalhada no menu Ajuda que você pode usar para identificar gargalos de desempenho em seu código. Além disso, os links a seguir fornecem mais informações sobre como utilizar APIs de threading do Visual Studio para otimizar seu código:

Você também pode usar os novos analisadores estáticos do Visual Studio para extensões (pacote NuGet aqui), que fornecem diretrizes sobre as práticas recomendadas para escrever extensões eficientes. Consulte uma lista de analisadores VSSDK e analisadores de threads.

Observação

Se você não conseguir resolver a falta de resposta devido a dependências sobre as quais não tem controle (por exemplo, se sua extensão precisar chamar serviços VS síncronos no thread da interface do usuário), gostaríamos de saber sobre isso. Se você for membro do nosso programa de Parceiros do Visual Studio, entre em contato conosco enviando uma solicitação de suporte ao desenvolvedor. Caso contrário, use a ferramenta "Relatar um Problema" para enviar seus comentários e incluir "Extension UI Delay Notifications" no título. Inclua também uma descrição detalhada de sua análise.