Risolvere i problemi relativi all'impatto del file di intestazione sul tempo di compilazione
Usare i file inclusi di Build Insights e includere le visualizzazioni albero per risolvere l'impatto dei file sui tempi di #include
compilazione C e C++.
Prerequisiti
- Visual Studio 2022 17.8 o versione successiva.
- Build Insights C++ è abilitato per impostazione predefinita se si installa il carico di lavoro Sviluppo di applicazioni desktop con C++ usando il programma di installazione di Visual Studio:
Viene visualizzato l'elenco dei componenti installati. Build Insights C++ è evidenziato ed è selezionato il che significa che è installato.
Oppure il carico di lavoro Sviluppo di giochi con C++:
Viene visualizzato l'elenco dei componenti installati. Build Insights C++ è evidenziato ed è selezionato il che significa che è installato.
Panoramica
Build Insights, ora integrato in Visual Studio, consente di ottimizzare i tempi di compilazione, in particolare per progetti di grandi dimensioni, ad esempio giochi triple A. Quando un file di intestazione di grandi dimensioni viene analizzato e soprattutto quando viene analizzato ripetutamente, si verifica un impatto sul tempo di compilazione.
Build Insights offre analisi nella visualizzazione File inclusi, che consente di diagnosticare l'impatto dell'analisi #include
dei file nel progetto. Visualizza il tempo necessario per analizzare ogni file di intestazione e una visualizzazione delle relazioni tra i file di intestazione.
Questo articolo illustra come usare i file inclusi di Build Insights e le visualizzazioni Includi albero per identificare i file di intestazione più costosi da analizzare e come ottimizzare il tempo di compilazione creando un file di intestazione precompilato.
Impostazione delle opzioni di compilazione
Prima di raccogliere i dati di Build Insights, impostare le opzioni di compilazione per il tipo di compilazione da misurare. Ad esempio, se si è interessati al tempo di compilazione del debug x64, impostare la compilazione per Debug e x64:
Nell'elenco a discesa Configurazioni soluzione scegliere Debug.
Nell'elenco a discesa Piattaforme soluzioni scegliere x64.
Viene visualizzato l'elenco a discesa Configurazione soluzione. Include opzioni per Debug, Release e Configuration Manager. L'elenco a discesa Piattaforma soluzioni è impostato su x64.
Eseguire Build Insights
In un progetto scelto e usando le opzioni di compilazione Debug impostate nella sezione precedente, eseguire Build Insights scegliendo dal menu principale Compila>Compila informazioni dettagliate sul <nome>>del progetto Ricompila. È anche possibile fare clic con il pulsante destro del mouse su un progetto in Esplora soluzioni e scegliere Esegui ricompilazione di Build Insights>. Scegliere Ricompila invece di Compila per misurare il tempo di compilazione per l'intero progetto e non solo per i pochi file potrebbero essere sporchi al momento.
Al termine della compilazione, viene aperto un file ETL (Event Trace Log). Viene salvato nella cartella a cui punta la variabile di ambiente Windows TEMP
. Il nome generato si basa sull'ora di raccolta.
Visualizzazione File inclusi
Il file di traccia mostra il tempo di compilazione, che per questo esempio è stato di 16,404 secondi. La sessione di diagnostica è il tempo complessivo impiegato per eseguire la sessione di Build Insights. Scegliere la scheda File inclusi.
Questa visualizzazione mostra il tempo impiegato per l'elaborazione dei #include
file.
Nella colonna percorso file sono evidenziati diversi file con un'icona di fuoco perché richiedono più del 10% del tempo di compilazione per l'analisi. winrtHeaders.h è il più grande a 8,581 secondi o al 52,3% del tempo di compilazione di 16,404 secondi.
Nella colonna Percorso file alcuni file hanno un'icona di fuoco accanto a essi per indicare che richiedono il 10% o più del tempo di compilazione.
La colonna Tempo [sec, %] mostra quanto tempo è necessario per compilare ogni funzione nel tempo di responsabilità dell'orologio a parete (WCTR).The Time [sec, %] column show how long it took to compile each function in wall clock responsibility time (WCTR). Questa metrica distribuisce il tempo necessario per analizzare i file in base all'uso di thread paralleli. Ad esempio, se due thread diversi analizzano due file diversi contemporaneamente entro un secondo periodo, il WCTR di ogni file viene registrato come 0,5 secondi. Ciò riflette la quota proporzionale di ogni file del tempo di compilazione totale, tenendo conto delle risorse utilizzate durante l'esecuzione parallela. Pertanto, WCTR fornisce una misura migliore dell'impatto di ogni file sul tempo di compilazione complessivo negli ambienti in cui si verificano più attività di compilazione contemporaneamente.
La colonna Parse Count mostra quante volte è stato analizzato il file di intestazione.
Il primo file di intestazione evidenziato in questo elenco richiede winrtHeaders.h
8,581 secondi del tempo di compilazione complessivo di 16,404 secondi o il 52,3% del tempo di compilazione. Il successivo più costoso è Windows.UI.Xaml.Interop.h
e quindi Windows.Xaml.h
.
Per visualizzare il file che include winrtHeaders.h
, fare clic sulla freccia di espansione accanto. La colonna Parse Count può essere utile indicando quante volte un file di intestazione è incluso da altri file. Forse un file di intestazione è incluso più volte, che potrebbe essere un segno che è un buon candidato per un file di intestazione precompilato o il refactoring.
La colonna Unità di traduzione mostra il file in corso di elaborazione durante l'elaborazione del file incluso. In questo esempio è winrtHeaders.h
stato incluso durante Grapher.cpp
la compilazione:
Esempio di file ETL che mostra i file di include per un progetto di esempio. Nella colonna percorso file winrtHeaders.h è selezionato ed espanso. La compilazione richiede 8,219 secondi, ovvero il 50,1% del tempo di compilazione. Il nodo figlio è Grapher.cpp, elencato anche come unità di conversione".
La colonna dell'unità di traduzione può aiutare a disambiguare il file compilato nei casi in cui un file di intestazione è incluso più volte e si vuole scoprire dove si verifica di più.
Sappiamo che winrtHeaders.h
è costoso da analizzare, ma possiamo ottenere altre informazioni.
Includi visualizzazione albero
In questa vista, i nodi figlio sono i file inclusi nel nodo padre. Ciò consente di comprendere le relazioni tra i file di intestazione e identificare le opportunità di ridurre il numero di volte in cui viene analizzato un file di intestazione.
Selezionare la scheda Includi albero nel file ETL per visualizzare la visualizzazione Includi albero:
Mostra l'albero di inclusione per un progetto. Nella colonna percorso file, ogni file che include altri file è elencato, insieme al numero di file inclusi e al tempo necessario per analizzarlo.
In questa visualizzazione la colonna Percorso file mostra ogni file che include altri file. Il conteggio di inclusione elenca il numero di file inclusi in questo file di intestazione. Il tempo necessario per analizzare questo file è elencato e, quando espanso, elenca il tempo necessario per analizzare ogni singolo file di intestazione incluso in questo file di intestazione.
In precedenza, si è visto che l'analisi winrtHeaders.h
richiede molto tempo. Nella casella di testo Filtra file, se si immette winrtHeaders.h
, è possibile filtrare la visualizzazione in modo che contenga solo le voci che contengono winrtHeaders.h
nel nome. Facendo clic sulla freccia di espansione accanto a winrtHeaders.h
vengono visualizzati i file inclusi:
La colonna percorso file elenca ogni file che include altri file, insieme al numero di file inclusi e al tempo necessario per analizzarlo. winrtHeaders.h è selezionato ed espanso per visualizzare i file inclusi. Windows.UI.Xaml.Interop.h è uno di questi file ed è espanso per mostrare Windows.UI.Xaml.Interop.h espanso per visualizzare i file di intestazione inclusi.
Si noterà che winrtHeaders.h
include Windows.UI.Xaml.Interop.h
. Tenere presente dalla visualizzazione File inclusi che l'analisi richiedeva molto tempo. Fare clic sulla freccia di espansione accanto a Windows.UI.Xaml.Interop.h
per vedere che include , che include Windows.UI.Xaml.h
21 altri file di intestazione, due dei quali sono presenti anche nell'elenco ad accesso frequente.
Dopo aver identificato alcuni dei file di intestazione più costosi da analizzare e vedendo che winrtHeaders.h
è responsabile dell'inserimento, suggerisce che è possibile usare un'intestazione precompilata per rendere più veloce l'inclusione winrtHeaders.h
.
Migliorare il tempo di compilazione con le intestazioni precompilate
Poiché è noto dalla visualizzazione File inclusi che winrtHeaders.h
richiede molto tempo per l'analisi e perché è noto dalla visualizzazione Albero di inclusione che winrtHeaders.h
include diversi altri file di intestazione che richiedono molto tempo per l'analisi, creiamo un file di intestazione precompilato (PCH) per velocizzarlo analizzandoli solo una volta in un PCH.
Si aggiunge un pch.h
oggetto per includere winrtHeaders.h
, che sarà simile al seguente:
#ifndef CALC_PCH
#define CALC_PCH
#include <winrtHeaders.h>
#endif // CALC_PCH
I file PCH devono essere compilati prima di poter essere usati, quindi si aggiunge un file al progetto, denominato pch.cpp
arbitrariamente , che include pch.h
. Contiene una riga:
#include "pch.h"
Quindi impostiamo il progetto per l'uso del PCH. Questa operazione viene eseguita nelle proprietà del progetto tramite intestazioni precompilate C/C++>e impostando Intestazione precompilata su Usa (/Yu) e File di intestazione precompilata su pch.h.
Intestazione precompilata è impostata su: Usa (/Yu). Il file di intestazione precompilato è impostato su pch.h.
Per usare pch, lo includiamo come prima riga nei file di origine che usano winrtHeaders.h
. Deve venire prima di qualsiasi altro file di inclusione. In alternativa, per semplicità, è possibile modificare le proprietà del progetto in modo da includere pch.h
all'inizio di ogni file nella soluzione impostando la proprietà del progetto: C/C++>Advanced Forced Include>File su :pch.h
Il file di inclusione forzato è impostato su pch.h.
Poiché il PCH include winrtHeaders.h
, è possibile rimuovere winrtHeaders.h
da tutti i file che attualmente lo includono. Non è strettamente necessario perché il compilatore si rende conto che winrtHeaders.h
è già incluso e non lo analizza di nuovo. Alcuni sviluppatori preferiscono conservare nel #include
file di origine per maggiore chiarezza o nel caso in cui pch sia probabile che venga eseguito il refactoring e che non includa più il file di intestazione.
Testare le modifiche
Prima di tutto si pulisce il progetto per assicurarsi di confrontare la compilazione degli stessi file di prima. Per pulire un solo progetto, fare clic con il pulsante destro del mouse sul progetto nella Esplora soluzioni e scegliere Solo progetto>Solo <nome prj.>
Poiché questo progetto usa ora un'intestazione precompilata (PCH), non si vuole misurare il tempo impiegato per la compilazione del PCH perché questo avviene una sola volta. A questo scopo, caricare il pch.cpp
file e scegliere CTRL+F7 per compilare solo il file. È anche possibile compilare questo file facendo clic con il pulsante destro del mouse pch.cpp
nel Esplora soluzioni e scegliendo Compile
.
A questo momento si eseguono nuovamente Build Insights nella Esplora soluzioni facendo clic con il pulsante destro del mouse sul progetto e scegliendo Project Only Run Build Insights on Build Insights (Esegui solo>compilazione nella compilazione). È anche possibile fare clic con il pulsante destro del mouse su un progetto in Esplora soluzioni e scegliere Esegui compilazione di Informazioni dettagliate>compilazione. Non vogliamo ricompilare questa volta perché ricompilare il PCH, che non vogliamo misurare. Il progetto è stato pulito in precedenza, il che significa che una compilazione normale compila tutti i file di progetto da misurare.
Quando vengono visualizzati i file ETL, si noterà che il tempo di compilazione è passato da 16,404 secondi a 6,615 secondi. Inserire winrtHeaders.h
nella casella di filtro e non viene visualizzato nulla. Ciò è dovuto al fatto che il tempo impiegato per l'analisi è ora trascurabile perché viene estratto dall'intestazione precompilata.
Questo esempio usa intestazioni precompilate perché sono una soluzione comune prima di C++20. Tuttavia, a partire da C++20, esistono altri modi, più veloci, meno fragili, per includere file di intestazione, ad esempio unità di intestazione e moduli. Per altre informazioni, vedere Confrontare unità di intestazione, moduli e intestazioni precompilate.
Spostarsi tra le visualizzazioni
Esistono alcune funzionalità di spostamento sia per i file inclusi che per le visualizzazioni Albero di inclusione:
- Fare doppio clic su un file (o premere INVIO) nei file inclusi o nell'albero di inclusione per aprire il codice sorgente per tale file.
- Fare clic con il pulsante destro del mouse su un file di intestazione per trovare il file nell'altra visualizzazione. Ad esempio, nella visualizzazione Fileinclusi fare clic con
winrtHeaders.h
il pulsante destro del mouse e scegliere Trova nell'albero di inclusione per visualizzarlo nella visualizzazione Includi albero.
In alternativa, è possibile fare clic con il pulsante destro del mouse su un file nella visualizzazione Includi albero per passare alla visualizzazione File inclusi.
Suggerimenti
- È possibile >salvare il file con nome ETL in un percorso più permanente per mantenere un record del tempo di compilazione. È quindi possibile confrontarlo con le build future per verificare se le modifiche migliorano il tempo di compilazione.
- Se si chiude inavvertitamente la finestra Build Insights, riaprirla individuando il
<dateandtime>.etl
file nella cartella temporanea. LaTEMP
variabile di ambiente Windows fornisce il percorso della cartella dei file temporanei. - Per esaminare i dati di Build Insights con Windows analizzatore prestazioni (WPA), fare clic sul pulsante Apri in WPA nella parte inferiore destra della finestra ETL.
- Trascinare le colonne per modificare l'ordine delle colonne. Ad esempio, è consigliabile spostare la colonna Ora come prima colonna. È possibile nascondere le colonne facendo clic con il pulsante destro del mouse sull'intestazione di colonna e deselezionando le colonne che non si desidera visualizzare.
- Le visualizzazioni File inclusi e Albero di inclusione forniscono una casella di filtro per trovare un file di intestazione a cui si è interessati. Corrisponde parzialmente al nome specificato.
- A volte il tempo di analisi segnalato per un file di intestazione è diverso a seconda del file che lo include. Ciò può essere dovuto all'interazione di diversi
#define
elementi che influiscono sulle parti dell'intestazione espanse, la memorizzazione nella cache dei file e altri fattori di sistema. - Se si dimentica il contenuto della visualizzazione File inclusi o Albero di inclusione, passare il puntatore del mouse sulla scheda per visualizzare una descrizione comando che descrive la visualizzazione. Ad esempio, se si passa il puntatore del mouse sulla scheda Includi albero , la descrizione comando indica: "Visualizza che mostra le statistiche di inclusione per ogni file in cui i nodi figlio sono i file inclusi nel nodo padre".
- È possibile che vengano visualizzati casi (ad esempio
Windows.h
) in cui la durata aggregata di tutti i tempi per un file di intestazione è superiore alla durata dell'intera compilazione. Ciò che accade è che le intestazioni vengono analizzate contemporaneamente su più thread. Se due thread impiegano simultaneamente un secondo di analisi di un file di intestazione, questo è di 2 secondi di tempo di compilazione anche se è passato solo un secondo di tempo di clock del muro. Per altre informazioni, vedere Tempo di responsabilità dell'orologio a parete (WCTR).
Risoluzione dei problemi
- Se la finestra Build Insights non viene visualizzata, eseguire una ricompilazione anziché una compilazione. La finestra Build Insights non viene visualizzata se non viene effettivamente compilata alcuna compilazione; che può essere il caso se nessun file è stato modificato dopo l'ultima compilazione.
- Se un file di intestazione a cui si è interessati non viene visualizzato nelle visualizzazioni File inclusi o Includi albero , non è stato compilato o il tempo di compilazione non è sufficientemente significativo da essere elencato.
Vedi anche
Creare suggerimenti e consigli analitici
Confrontare unità di intestazione, moduli e intestazioni precompilate
Video di Build Insights in Visual Studio - Pure Virtual C++ 2023
Compilazioni C++ più veloci, semplificate: una nuova metrica per il tempo
Risolvere i problemi di inlining della funzione in fase di compilazione
vcperf e Windows analizzatore prestazioni