Partilhar via


Solucionar problemas de impacto do arquivo de cabeçalho no tempo de compilação

Use as visualizações de ficheiros incluídos no Build Insights e de árvore de inclusão para resolver problemas relacionados com o impacto dos ficheiros nos tempos de compilação C e C++.

Pré-requisitos

  • Visual Studio 2022 17.8 ou superior.
  • O C++ Build Insights é habilitado por padrão se você instalar o desenvolvimento de área de trabalho com carga de trabalho C++ usando o instalador do Visual Studio:

Captura de ecrã do Instalador do Visual Studio com a tarefa 'Desenvolvimento para ambiente de trabalho com C++' selecionada.

A lista de componentes instalados é mostrada. O C++ Build Insights é realçado e selecionado, o que significa que está instalado.

Ou o desenvolvimento de jogos com C++:

Captura de tela do instalador do Visual Studio com a carga de trabalho de desenvolvimento de jogos com C++ selecionada.

A lista de componentes instalados é mostrada. O C++ Build Insights é realçado e selecionado, o que significa que está instalado.

Visão geral

O Build Insights, agora integrado ao Visual Studio, ajuda você a otimizar seus tempos de compilação, especialmente para grandes projetos, como jogos triple-A. Quando um arquivo de cabeçalho grande é analisado, e especialmente quando é analisado repetidamente, há um impacto no tempo de compilação.

O Build Insights fornece análises na visualização Arquivos incluídos , que ajuda a diagnosticar o impacto da análise de #include arquivos em seu projeto. Ele exibe o tempo que leva para analisar cada arquivo de cabeçalho e uma exibição das relações entre arquivos de cabeçalho.

Neste artigo, saiba como usar as visualizações Build Insights Included Files e Include Tree para identificar os arquivos de cabeçalho mais caros para analisar e como otimizar o tempo de compilação criando um arquivo de cabeçalho pré-compilado.

Definir opções de compilação

Antes de coletar dados do Build Insights, defina as opções de compilação para o tipo de compilação que você deseja medir. Por exemplo, se você estiver preocupado com o tempo de compilação da depuração x64, defina a compilação para Debug e x64:

  • No menu suspenso Configurações da Solução , escolha Depurar.

  • No menu suspenso Plataformas de Solução , escolha x64.

    Captura de ecrã dos menus dropdown Configuração da Solução.

    A lista suspensa da Configuração da Solução é mostrada. Ele tem opções para Depurar, Compilação e Gestor de Configurações. A lista suspensa Plataforma de Soluções está definida para x64.

Executar Build Insights

Em um projeto de sua escolha, e usando as opções de compilação Debug definidas na seção anterior, execute Build Insights escolhendo no menu principal Build>Run Build Insights no <nome>> do projetoRebuild. Você também pode clicar com o botão direito do mouse em um projeto no gerenciador de soluções e escolher Executar Build Insights>Rebuild. Escolha Reconstruir em vez de Construir para medir o tempo de compilação para todo o projeto e não apenas para os poucos arquivos que podem estar sujos agora.

Captura de ecrã do menu principal com a opção Run Build Insights on Selection > Rebuild selecionada.

Quando a compilação termina, um arquivo ETL (Event Trace Log) é aberto. Ele é salvo na pasta apontada pela variável de ambiente Windows TEMP . O nome gerado é baseado no tempo de coleta.

Visualização de arquivos incluídos

O arquivo de rastreamento mostra o tempo de compilação - que, para este exemplo, foi de 16,404 segundos. A Sessão de Diagnóstico é o tempo total necessário para executar a sessão do Build Insights. Escolha a guia Arquivos incluídos .

Esta vista mostra o tempo gasto no processamento #include de ficheiros.

Captura de ecrã da vista de ficheiros incluídos.

Na coluna do caminho de ficheiros, vários ficheiros com um ícone de fogo são destacados porque demoram mais de 10% do tempo de construção para serem analisados. winrtHeaders.h é o maior, com 8.581 segundos ou 52.3% do tempo de compilação de 16.404 segundos.

Na coluna Caminho do arquivo , alguns arquivos têm um ícone de fogo ao lado deles para indicar que ocupam 10% ou mais do tempo de compilação.

A coluna Tempo [seg, %] mostra quanto tempo levou para compilar cada função em tempo de responsabilidade do relógio de parede (WCTR). Esta métrica distribui o tempo real necessário para analisar arquivos de acordo com o uso de threads paralelos. Por exemplo, se dois threads diferentes estiverem analisando dois arquivos diferentes simultaneamente dentro de um período de um segundo, o WCTR de cada arquivo será registrado como 0,5 segundos. Isso reflete a parte proporcional de cada arquivo no tempo total de compilação, levando em consideração os recursos que cada um consumiu durante a execução paralela. Assim, o WCTR fornece uma melhor medida do impacto que cada arquivo tem no tempo geral de compilação em ambientes onde várias atividades de compilação ocorrem simultaneamente.

A coluna Contagem de Análises mostra quantas vezes o arquivo de cabeçalho foi analisado.

O primeiro arquivo de cabeçalho destacado nesta lista é winrtHeaders.h Leva 8,581 segundos do tempo total de compilação de 16,404 segundos, ou 52,3% do tempo de compilação. O próximo mais caro é Windows.UI.Xaml.Interop.h, e depois Windows.Xaml.h.

Para ver que ficheiro inclui winrtHeaders.h, clique na seta ao lado dele. A coluna Contagem de Análises pode ser útil apontando quantas vezes um arquivo de cabeçalho é incluído por outros arquivos. Talvez um arquivo de cabeçalho seja incluído várias vezes, o que pode ser um sinal de que é um bom candidato para um arquivo de cabeçalho pré-compilado ou refatoração.

A coluna Unidade de tradução mostra qual arquivo estava sendo processado quando o arquivo incluído foi processado. Neste exemplo, winrtHeaders.h foi incluído enquanto Grapher.cpp foi compilado:

Captura de ecrã da vista Ficheiros incluídos.

Um arquivo ETL de exemplo mostrando os arquivos incluídos para um projeto de exemplo. Na coluna caminho do arquivo, winrtHeaders.h é selecionado e expandido. Leva 8,219 segundos para construir, o que é 50,1% do tempo de compilação. Seu nó filho é Grapher.cpp, que também é listado como a unidade de tradução."

A coluna da unidade de tradução pode ajudar a desambiguar qual arquivo estava sendo compilado nos casos em que um arquivo de cabeçalho é incluído muitas vezes e você quer descobrir onde isso acontece mais.

Sabemos que winrtHeaders.h é caro analisar, mas podemos aprender mais.

Incluir vista em árvore

Nessa exibição, os nós filhos são os arquivos incluídos pelo nó pai. Isso pode ajudá-lo a entender as relações entre arquivos de cabeçalho e identificar oportunidades para reduzir o número de vezes que um arquivo de cabeçalho é analisado.

Selecione a guia Incluir árvore no arquivo ETL para ver a visualização Incluir árvore:

Captura de ecrã da visão de inclusão em árvore.

Mostra a árvore de inclusão de um projeto. Na coluna caminho do arquivo, cada arquivo que inclui outros arquivos é listado, juntamente com quantos arquivos ele inclui e o tempo para analisá-lo.

Nesta vista, a coluna Caminho do Ficheiro mostra cada ficheiro que inclui outros ficheiros. A contagem de inclusão lista quantos arquivos esse arquivo de cabeçalho inclui. O tempo para analisar esse arquivo é listado e, quando expandido, lista o tempo para analisar cada arquivo de cabeçalho individual que esse arquivo de cabeçalho inclui.

Anteriormente, vimos que a winrtHeaders.h análise é demorada. Na caixa de texto Filtrar Ficheiros , se introduzirmos winrtHeaders.h, podemos filtrar a vista apenas para as entradas que contêm winrtHeaders.h o nome. Clicar na divisa ao lado de winrtHeaders.h mostra quais são os ficheiros que inclui:

Captura de ecrã da vista expandida da Árvore de Inclusão.

A coluna de caminho do arquivo lista cada arquivo que inclui outros arquivos, juntamente com quantos arquivos ele inclui e o tempo que levou para analisá-lo. winrtHeaders.h é selecionado e expandido para mostrar os arquivos que inclui. Windows.UI.Xaml.Interop.h é um desses arquivos e é expandido para mostrar Windows.UI.Xaml.Interop.h que é expandido para mostrar os arquivos de cabeçalho que inclui.

Vemos que winrtHeaders.h inclui Windows.UI.Xaml.Interop.h. Lembre-se, na visualização Arquivos incluídos , de que a análise também era demorada. Clique na divisa ao lado de Windows.UI.Xaml.Interop.h para ver que inclui Windows.UI.Xaml.h, que inclui outros 21 ficheiros de cabeçalho, dois dos quais também estão na lista quente.

Tendo identificado alguns dos arquivos de cabeçalho mais caros para analisar, e vendo que winrtHeaders.h é responsável por trazê-los, sugere que podemos usar um cabeçalho pré-compilado para tornar a inclusão winrtHeaders.h mais rápida.

Melhore o tempo de compilação com cabeçalhos pré-compilados

Como sabemos pela visualização Arquivos incluídos que winrtHeaders.h é demorada para analisar, e porque sabemos pela visualização Incluir árvore que winrtHeaders.h inclui vários outros arquivos de cabeçalho que são demorados para analisar, criamos um arquivo de cabeçalho pré-compilado (PCH) para acelerar isso, analisando-os apenas uma vez em um PCH.

Adicionamos um pch.h para incluir winrtHeaders.h, que ficaria assim:

#ifndef CALC_PCH
#define CALC_PCH

#include <winrtHeaders.h>

#endif // CALC_PCH

Os arquivos PCH devem ser compilados antes de poderem ser usados, então adicionamos um arquivo ao projeto, nomeado pch.cpparbitrariamente, que inclui pch.h. Contém uma linha:

#include "pch.h"

Então definimos nosso projeto para usar a PCH. Isso é feito nas propriedades do projeto via C/C++>Cabeçalhos pré-compilados e definindo Cabeçalho pré-compilado para usar (/Yu) e Arquivo de cabeçalho pré-compilado para pch.h.

Captura de tela da caixa de diálogo de propriedades do projeto com as configurações de Cabeçalhos pré-compilados abertas.

O cabeçalho pré-compilado está definido como: Use (/Yu). O arquivo de cabeçalho pré-compilado é definido como pch.h.

Para usar a PCH, incluímo-la como a primeira linha nos arquivos de origem que usam winrtHeaders.h. Ele deve vir antes de qualquer outro arquivo de inclusão. Ou, para simplificar, podemos modificar as propriedades do projeto para incluir pch.h no início de cada arquivo na solução, definindo a propriedade do projeto: C/C++>Advanced>Forced Include File como pch.h:

Captura de tela da caixa de diálogo de propriedades do projeto com as Configurações avançadas abertas.

O ficheiro de inclusão forçada está definido como pch.h.

Uma vez que o PCH inclui winrtHeaders.h, poderíamos remover winrtHeaders.h de todos os arquivos que atualmente o incluem. Não é estritamente necessário porque o compilador percebe que winrtHeaders.h já está incluído e não o analisa novamente. Alguns desenvolvedores preferem manter o #include no arquivo de origem para maior clareza, ou no caso de o PCH provavelmente ser refatorado e pode não incluir mais esse arquivo de cabeçalho.

Testar as alterações

Primeiro, limpamos o projeto para ter certeza de que estamos comparando a construção dos mesmos arquivos de antes. Para limpar apenas um projeto, clique com o botão direito do mouse no projeto no Gerenciador de Soluções e escolha Somente projeto>Limpar somente <nome> prj.

Como este projeto agora usa um cabeçalho pré-compilado (PCH), não queremos medir o tempo gasto na construção do PCH porque isso só acontece uma vez. Fazemos isso carregando o pch.cpp arquivo e escolhendo Ctrl+F7 para construir apenas esse arquivo. Também podemos compilar esse arquivo clicando com pch.cpp o botão direito do mouse no Gerenciador de Soluções e escolhendo Compile.

Agora, executamos novamente o Build Insights no Gerenciador de Soluções clicando com o botão direito do mouse no projeto e escolhendo Project Only>Run Build Insights on Build. Você também pode clicar com o botão direito do mouse em um projeto no Gerenciador de Soluções e escolher Executar Compilação do Build Insights>Compilação. Não queremos Reconstruir desta vez porque isso vai reconstruir a PCH, que não queremos medir. Nós limpamos o projeto anteriormente, o que significa que uma compilação normal compila todos os arquivos de projeto que queremos medir.

Quando os arquivos ETL aparecem, vemos que o tempo de compilação passou de 16,404 segundos para 6,615 segundos. Coloque winrtHeaders.h na caixa de filtro e nada aparece. Isso ocorre porque o tempo gasto analisando-o agora é insignificante, uma vez que está sendo puxado pelo cabeçalho pré-compilado.

Captura de ecrã do painel Árvore de Inclusão no ficheiro de rastreamento. winrtHeaders não está mais listado.

Este exemplo usa cabeçalhos pré-compilados porque eles são uma solução comum antes do C++20. No entanto, a partir do C++20, existem outras maneiras mais rápidas e menos frágeis de incluir arquivos de cabeçalho, como unidades de cabeçalho e módulos. Para obter mais informações, consulte Comparar unidades de cabeçalho, módulos e cabeçalhos pré-compilados.

Existem alguns recursos de navegação para os modos de exibição Arquivos incluídos e Árvore de inclusão :

  • Clique duas vezes em um arquivo (ou pressione Enter) em Arquivos incluídos ou Árvore de inclusão para abrir o código-fonte desse arquivo.
  • Clique com o botão direito do rato num ficheiro de cabeçalho para localizar esse ficheiro na outra vista. Por exemplo, na vista Ficheiros incluídos, clique com o botão direito winrtHeaders.h e escolha Localizar na Árvore de Inclusão para vê-la na vista Árvore de Inclusão.

Captura de ecrã de um clique com o botão direito do rato num ficheiro na vista Ficheiros incluídos. A opção de menu Mostrar em Incluir Vista em Árvore está realçada.

Ou, você pode clicar com o botão direito do mouse em um arquivo no modo de exibição Incluir árvore para ir até ele no modo de exibição Arquivos incluídos .

Sugestões

  • Você pode Salvar como> o arquivo ETL em um local mais permanente para manter um registro do tempo de compilação. Em seguida, você pode compará-lo com compilações futuras para ver se suas alterações estão melhorando o tempo de compilação.
  • Se você fechar inadvertidamente a janela do Build Insights, abra-a novamente localizando o <dateandtime>.etl arquivo em sua pasta temporária. A TEMP variável de ambiente do Windows fornece o caminho da pasta de arquivos temporários.
  • Para explorar os dados do Build Insights com o Windows Performance Analyzer (WPA), clique no botão Abrir no WPA no canto inferior direito da janela ETL.
  • Arraste colunas para alterar a ordem das colunas. Por exemplo, você pode preferir mover a coluna Hora para ser a primeira coluna. Você pode ocultar colunas clicando com o botão direito do mouse no cabeçalho da coluna e desmarcando as colunas que não deseja ver.
  • As visualizações Arquivos incluídos e Árvore de inclusão fornecem uma caixa de filtro para localizar um arquivo de cabeçalho no qual você está interessado. Ele faz correspondências parciais no nome que você fornece.
  • Às vezes, o tempo de análise relatado para um arquivo de cabeçalho é diferente, dependendo de qual arquivo o inclui. Isso pode ser devido à interação de diferentes #defines que afetam quais partes do cabeçalho são expandidas, cache de arquivos e outros fatores do sistema.
  • Se você esquecer o que o modo de exibição Arquivos Incluídos ou Árvore de Inclusão está tentando mostrar, passe o mouse sobre a guia para ver uma dica de ferramenta que descreve o modo de exibição. Por exemplo, se tu passares o rato sobre o separador Árvore de Inclusão, a dica de ferramenta diz: "Visualização que apresenta estatísticas de inclusão para cada ficheiro, onde os nós filhos são os ficheiros incluídos pelo nó pai."
  • Você pode ver casos (como Windows.h) em que a duração agregada de todos os tempos de um arquivo de cabeçalho é maior do que a duração de toda a compilação. O que está acontecendo é que os cabeçalhos estão sendo analisados em vários threads ao mesmo tempo. Se dois threads gastarem simultaneamente um segundo analisando um arquivo de cabeçalho, isso significa 2 segundos de tempo de construção, mesmo que apenas um segundo de tempo de relógio de parede tenha passado. Para obter mais informações, consulte Tempo de responsabilidade do relógio de parede (WCTR).

Solução de problemas

  • Se a janela Build Insights não aparecer, faça uma reconstrução em vez de uma compilação. A janela Build Insights não aparece se nada realmente for compilado; o que pode ser o caso se nenhum arquivo foi alterado desde a última compilação.
  • Se um arquivo de cabeçalho em que você está interessado não aparecer nas visualizações Arquivos incluídos ou Incluir árvore , ele não foi criado ou seu tempo de compilação não é significativo o suficiente para ser listado.

Ver também

Dicas e truques do Build Insights
Comparar unidades de cabeçalho, módulos e cabeçalhos pré-compilados
Vídeo Criar insights no Visual Studio - Pure Virtual C++ 2023
Compilações C++ mais rápidas, simplificadas: uma nova métrica para o tempo
Solucionar problemas de integração de funções no tempo de compilação
vcperf e Windows Performance Analyzer