Exercício 3 – Entender o caminho crítico e a análise de espera
Cenários e atividades podem ser inesperadamente atrasados. Por exemplo, abrir uma guia no Microsoft Edge pode demorar mais do que o esperado.
Uma atividade é definida como uma série de operações, algumas sequenciais e algumas paralelas, que fluem de um evento inicial para um evento final. Qualquer par de eventos de início/término em um rastreamento pode ser exibido como uma atividade. O caminho mais longo por essa série de operações é conhecido como o caminho crítico. Reduzir a duração de qualquer operação no caminho crítico reduz diretamente a duração da atividade geral.
É recomendável que você identifique o processo e o thread que concluiu a atividade e trabalhe para trás a partir do momento em que a atividade foi concluída. Comece analisando o thread que concluiu a atividade para determinar como esse thread passou a maior parte do tempo e em que estado: em execução, pronto ou aguardando.
Tempos de execução significativos indicam que o uso direto da CPU pode estar contribuindo para a duração do caminho crítico. O tempo gasto no estado pronto indica que outros threads contribuem para a duração do caminho crítico, impedindo que um thread no caminho crítico seja executado. Tempo gasto aguardando pontos para E/S, temporizadores ou outros threads e processos no caminho crítico para o qual o thread atual estava aguardando.
Cada thread que lê o thread atual provavelmente é outro link no caminho crítico e também pode ser analisado até que a duração do caminho crítico seja contabilizado.
Todas as informações necessárias são registradas no grafo e na tabela Uso da CPU (Preciso) no WPA. Os eventos de uso da CPU registrados pelo dispatcher são associados a comutadores de contexto. Esta tabela se concentra em NewThread , que é o thread que foi alternado e cada linha representa uma opção de contexto. Os dados são coletados para a seguinte sequência de eventos:
NewThread é alternado devido a uma chamada de função de bloqueio.
NewThread está pronto para ser executado pelo thread de preparação.
NewThread é alternado para dentro, alternando assim um thread antigo.
NewThread é alternado novamente.
Aqui estão as colunas interessantes na tabela Uso da CPU (Preciso ).
Coluna | Detalhes |
---|---|
% de uso da CPU | O uso da CPU do novo thread depois que ele é alternado. Esse valor é expresso como uma porcentagem do tempo total da CPU durante o período de tempo visível no momento. |
Count | O número de opções de contexto representadas pela linha. Isso é sempre 1 para linhas individuais. |
Uso da CPU (ms) | O uso da CPU do novo thread após a opção de contexto. |
NewProcess | O processo do novo thread. |
NewThreadId | A ID do thread do novo thread. |
NewThreadStack | A pilha do novo thread quando ele é alternado. Geralmente indica o que o thread foi bloqueado ou aguardando. |
Ready(s) | O tempo que o thread gastou na fila Pronto (devido ao vazio ou à falta de CPU). |
ReadyingThreadId | A ID do thread de preparação. |
ReadyingProcess | O processo que possui o thread de preparação. |
ReadyThreadStack | A pilha do thread de preparação. |
ReadyTime (s) | A hora em que o novo thread foi preparado. |
SwitchInTime(s) | A hora em que o novo thread foi alternado. |
Esperas (s) | A quantidade de tempo que um thread esperou em um recurso lógico ou físico. A espera termina quando NewThreadId é sinalizado por ReadyingThreadId. |
Etapa 1: Capturar e abrir um rastreamento para um problema de atraso da interface do usuário
Este exercício se concentrará em um processo fictício com uma interface do usuário sem resposta. O processo é um aplicativo simples do Windows Form com um botão e uma caixa de texto. Quando o botão é clicado, a interface do usuário fica sem resposta por 20 segundos até que a caixa de texto seja atualizada. Você analisará o caminho crítico dessa operação.
Baixe UIDelay.exeaqui.
Inicie UIDelay.exe.
Abra o WPR no menu Iniciar .
Modifique a configuração de rastreamento.
Selecione Triagem de Primeiro Nível e Uso da CPU.
Selecione Geral como o cenário de desempenho.
Selecione Detalhado como o nível de detalhes.
Clique em Iniciar.
Em UIDelay.exe, clique no botão Clicar .
- Aguarde até que a caixa de texto mostre "Concluído!"
No WPR, salve o rastreamento e abra-o com o WPA.
Abra o menu Rastreamento e selecione Configurar caminho de símbolos.
- Especifique o caminho do cache de símbolos. Para obter mais informações sobre símbolos, consulte a página Suporte a Símbolos no MSDN.
Abra o menu Rastreamento e selecione Carregar símbolos.
Etapa 2: identificar o thread de interface do usuário atrasado
Antes de executar a análise crítica do caminho, primeiro você deve identificar os eventos de início e parada da atividade.
Localize o grafo Atrasos da interface do usuário no nó Atividade do Sistema da Explorer do Graph.
Arraste e solte o grafo Atrasos da interface do usuário na guia análise.
Localize o processo deUIDelay.exe .
Sua duração deve ser de cerca de 20 segundos. Isso indica que houve um atraso de 20 segundos no thread da interface do usuário do UIDelay.exe.
O identificador de thread da interface do usuário é mostrado na coluna ID do thread . Neste exemplo, é 24174. Esse valor será diferente no rastreamento que você capturou em seu computador. Anote a ID do thread.
Selecione todo o intervalo de tempo UIDelay.exe , clique com o botão direito do mouse e amplie.
Você sempre deve ampliar as regiões que está tentando analisar. Ele reduz a quantidade de ruído introduzida por atividades não relacionadas.
Etapa 3: Analisar o caminho crítico de atraso da interface do usuário
Agora que você tem um ponto de partida de análise com a ID do thread e os carimbos de data/hora, você pode começar a pesquisar o caminho crítico da atividade para entender a sequência de eventos que levam a um atraso de 20 segundos no thread da interface do usuário.
O NewThreadId para esta etapa é o thread que você identificou na Etapa 2 (Thread 24174 em UIDelay.exe processo).
Adicione o grafo Uso da CPU (Preciso) à guia análise e aplique a predefinição Utilização por Processo, Thread .
Clique com o botão direito do mouse nos cabeçalhos da coluna e torne as colunas NewThreadStack, ReadyThreadStack e Uso da CPU (ms) visíveis.
Remova as colunas Ready (us) [Max] e Waits (us) [Max] . Seu visor agora deve ter esta aparência.
Localize e expanda o processo deUIDelay.exe na coluna NewProcess e classifique por Esperas (nós) [Soma] clicando no cabeçalho da coluna.
Pesquise o NewThreadId no processo deUIDelay.exe e analise o tempo gasto no estado Executando, Pronto ou Aguardando.
No exemplo a seguir, você pode descobrir que:
O thread está consumindo 10,025 segundos de tempo de CPU.
O thread está aguardando 5,159 segundos.
O thread está no estado pronto por uma quantidade insignificante de tempo (10ms).
Nota Você pode analisar os 10 segundos de atividade da CPU usando a mesma metodologia descrita no Exercício 2, Etapa 4 usando o grafo Uso da CPU (amostra) e examinando o processo deUIDelay.exe .
Para descobrir o que o NewThreadId estava esperando, expanda o grupo NewThreadId para exibir o NewThreadStack.
Expanda [Raiz] e identifique as chamadas de função que levam a esperas.
Neste exemplo, UIDelay.exe ID de thread 24174 está aguardando chamadas de função de bloqueio subjacentes por 5,073 segundos quando a função de clique do botão é disparada:
5,021 segundos são devido a operações abaixo da função ExecuteWMICall .
35 ms são devido a operações abaixo da função PingServer .
Etapa 3.1: Examinar o caminho do código ExecuteWMICall
Se você expandir ainda mais a pilha de chamadas em ExecuteWMICall, descobrirá que o thread da interface do usuário está realmente em suspensão por 5 segundos chamando explicitamente Thread.Sleep.
Esse tipo de comportamento deve ser evitado a todo custo, pois afeta diretamente a capacidade de resposta. Se o código precisar aguardar informações, ele deverá fazê-lo de forma assíncrona em um thread separado e usar um método controlado por eventos.
Etapa 3.2: Examinar o código PingServer
Se você expandir ainda mais a pilha de chamadas em PingServer, descobrirá que o thread de interface do usuário tem dependências de E/S, pois está enviando comandos ping pela rede.
Embora o atraso seja muito pequeno (35 ms), ele deve ser evitado em um thread de interface do usuário. Tenha em mente que a pessoa comum observará qualquer atraso de interface do usuário maior que 100 ms. Essa operação pode aumentar o tempo total decorrido da atividade acima de 100 ms, resultando em usuários com uma percepção ruim de capacidade de resposta.
Essas operações devem ocorrer de forma assíncrona em um thread separado e não bloquear a interface do usuário.