Solución de problemas del impacto del archivo de encabezado en el tiempo de compilación
Utilice las vistas Archivos incluidos y Árbol de inclusión de Build Insights para solucionar el impacto de los archivos #include
en los tiempos de compilación de C y C++.
Requisitos previos
- Visual Studio 2022 17.8 o posterior.
- Build Insights para C++ está habilitado de manera predeterminada si instala la carga de trabajo Desarrollo de escritorio con C++ mediante el instalador de Visual Studio:
Se muestra la lista de componentes instalados. Build Insights para C++ está resaltado y está seleccionado, lo que significa que está instalado.
O bien, la carga de trabajo Desarrollo de juegos con C++:
Se muestra la lista de componentes instalados. Build Insights para C++ está resaltado y está seleccionado, lo que significa que está instalado.
Información general
Build Insights, ahora integrado en Visual Studio, le ayuda a optimizar los tiempos de compilación, especialmente para proyectos grandes como los juegos triple A. Cuando se analiza un archivo de encabezado grande y, especialmente cuando se analiza repetidamente, se produce un impacto en el tiempo de compilación.
Build Insights proporciona un análisis en la vista Archivos incluidos, lo que ayuda a diagnosticar el impacto del análisis de los archivos #include
en el proyecto. Muestra el tiempo necesario para analizar cada archivo de encabezado y una vista de las relaciones entre los archivos de encabezado.
En este artículo, aprenderá a usar las vistas Archivos incluidos y Árbol de inclusión para identificar los archivos de encabezado más costosos de analizar y cómo optimizar el tiempo de compilación mediante la creación de un archivo de encabezado precompilado.
Establecer las opciones de compilación
Antes de recopilar datos de Build Insights, establezca las opciones de compilación para el tipo de compilación que desea medir. Por ejemplo, si le preocupa el tiempo de compilación de depuración para x64, establezca la compilación para Depurar y x64:
En la lista desplegable Configuraciones de la solución, elija Depurar.
En la lista desplegable Plataformas de la solución, elija x64.
Se muestra la lista desplegable Configuración de la solución. Tiene opciones para Depurar, Versión y Configuration Manager. La lista desplegable Plataforma de la solución está establecida en x64.
Ejecución de Build Insights
En un proyecto de su elección y con las opciones de compilación de depuración establecidas en la sección anterior, ejecute Build Insights eligiendo en el menú principal Build Run Build Insights on project name Rebuild (Compilar Run>Build Insights on <project name>>Rebuild). También puede hacer clic con el botón derecho en un proyecto en el Explorador de soluciones y elegir Ejecutar Build Insights>Volver a compilar. Elija Volver a compilar en lugar de Compilar para medir el tiempo de compilación de todo el proyecto y no solo para unos pocos archivos que puedan estar incorrectos ahora mismo.
Cuando finaliza la compilación, se abre un archivo registro de seguimiento de eventos (ETL). Se guarda en la carpeta a la que apunta la variable de entorno de Windows TEMP
. El nombre generado se basa en la hora de recopilación.
Vista Archivos incluidos
El archivo de seguimiento muestra el tiempo de compilación, que para este ejemplo era de 16,404 segundos. El valor de Sesión de diagnóstico es el tiempo total necesario para ejecutar la sesión de Build Insights. Elija la pestaña Archivos incluidos.
Esta vista muestra el tiempo invertido en procesar los archivos #include
.
En la columna de ruta de acceso de archivo, se resaltan varios archivos con un icono de llama porque tardan más del 10 % del tiempo de compilación en analizarse. winrtHeaders.h es el más grande, con 8,581 segundos o un 52,3 % del tiempo de compilación de 16,404 segundos.
En la columna Ruta de acceso de archivo, algunos archivos tienen un icono de llama junto a ellos para indicar que tardan un 10 % o más del tiempo de compilación.
La columna Tiempo [seg, %] muestra cuánto tiempo se tarda en compilar cada función en tiempo de responsabilidad del reloj de pared (WCTR). Esta métrica distribuye el tiempo de reloj de pared que se tarda en analizar los archivos en función de su uso de subprocesos en paralelo. Por ejemplo, si dos subprocesos diferentes analizan dos archivos diferentes simultáneamente en un período de un segundo, el WCTR de cada archivo se registra como 0,5 segundos. Esto refleja la cuota proporcional de cada archivo del tiempo total de compilación, teniendo en cuenta los recursos consumidos durante la ejecución en paralelo. Por lo tanto, el WCTR proporciona una mejor medida del impacto que tiene cada archivo en el tiempo de compilación general en entornos donde se producen simultáneamente varias actividades de compilación.
La columna Recuento de análisis muestra cuántas veces se ha analizado el archivo de encabezado.
El primer archivo de encabezado resaltado en esta lista es winrtHeaders.h
, que emplea 8,581 segundos del tiempo de compilación total de 16,404 segundos, o un 52,3 % del tiempo de compilación. El siguiente más costoso es Windows.UI.Xaml.Interop.h
y, a continuación, Windows.Xaml.h
.
Para ver qué archivo incluye a winrtHeaders.h
, haga clic en el botón de contenido adicional situado junto a él. La columna Recuento de análisis puede resultar útil al señalar cuántas veces incluyen otros archivos un archivo de encabezado. Quizás se incluya un archivo de encabezado varias veces, lo que podría ser un signo de que es un buen candidato para un archivo de encabezado precompilado o para la refactorización.
La columna Unidad de traducción muestra qué archivo se estaba procesando cuando se procesó el archivo incluido. En este ejemplo, se incluyó el archivo winrtHeaders.h
mientras se compilaba el archivo Grapher.cpp
:
Archivo ETL de ejemplo que muestra los archivos de inclusión de un proyecto de ejemplo. En la columna Ruta de acceso del archivo, el archivo winrtHeaders.h está seleccionado y expandido. Tarda 8,219 segundos en compilarse, que representa el 50,1 % del tiempo de compilación. Su nodo secundario es Grapher.cpp, que también aparece como unidad de traducción.
La columna Unidad de traducción puede ayudar a eliminar la ambigüedad sobre qué archivo se estaba compilando en los casos en los que se incluye un archivo de encabezado muchas veces y se desea averiguar dónde sucede más.
Sabemos que winrtHeaders.h
es costoso de analizar, pero podemos obtener más información.
Vista Árbol de inclusión
En esta vista, los nodos secundarios son los archivos incluidos por el nodo primario. Esto puede ayudarle a comprender las relaciones entre los archivos de encabezado e identificar oportunidades para reducir el número de veces que se analiza un archivo de encabezado.
Seleccione la pestaña Árbol de inclusión en el archivo ETL para ver la vista Árbol de inclusión:
Muestra el árbol de inclusión de un proyecto. En la columna Ruta de acceso de archivo, se muestra cada archivo que incluye otros archivos, junto con el número de archivos que incluye y el tiempo necesario para analizarlo.
En esta vista, la columna Ruta de acceso de archivo muestra cada archivo que incluye otros archivos. El elemento Recuento de inclusiones enumera cuántos archivos incluye este archivo de encabezado. Se muestra el tiempo para analizar este archivo y, cuando se expande, muestra el tiempo para analizar cada archivo de encabezado individual que incluye este archivo de encabezado.
Anteriormente, vimos que el análisis de winrtHeaders.h
consume mucho tiempo. En el cuadro de texto Filtrar archivos, si especificamos winrtHeaders.h
, podemos filtrar la vista solo a las entradas que contienen winrtHeaders.h
en el nombre. Al hacer clic en el botón de contenido adicional situado junto a winrtHeaders.h
, se muestran los archivos que incluye:
La columna Ruta de acceso de archivo enumera cada archivo que incluye otros archivos, junto con el número de archivos que incluye y el tiempo necesario para analizarlo. El archivo winrtHeaders.h está seleccionado y expandido para mostrar los archivos que incluye. Windows.UI.Xaml.Interop.h es uno de esos archivos y está expandido para mostrar los archivos de encabezado que incluye.
Vemos que el archivo winrtHeaders.h
incluye el archivo Windows.UI.Xaml.Interop.h
. Recuerde que en la vista Archivos incluidos esto también consumía mucho tiempo para analizarse. Haga clic en el botón de contenido adicional situado junto a Windows.UI.Xaml.Interop.h
para ver que incluye el archivo Windows.UI.Xaml.h
, que a su vez incluye otros 21 archivos de encabezado, dos de los cuales también están en la lista activa.
Después de identificar algunos de los archivos de encabezado más costosos de analizar y ver que el archivo winrtHeaders.h
es el responsable de incorporarlos, sugiere que podemos usar un encabezado precompilado para que la inclusión de winrtHeaders.h
sea más rápida.
Mejora del tiempo de compilación con encabezados precompilados
Dado que sabemos por la vista Archivos incluidos que winrtHeaders.h
tarda mucho en analizarse y, dado que sabemos por la vista Árbol de inclusión que winrtHeaders.h
incluye otros archivos de encabezado que tardan mucho tiempo en analizarse, creamos un archivo de encabezado precompilado (PCH) para agilizarlo al analizarlos solo una vez en un archivo PCH.
Agregamos un archivo pch.h
para incluir winrtHeaders.h
, que tendría este aspecto:
#ifndef CALC_PCH
#define CALC_PCH
#include <winrtHeaders.h>
#endif // CALC_PCH
Los archivos PCH se deben compilar para poder usarlos, por lo que agregamos un archivo al proyecto, llamado arbitrariamente pch.cpp
, que incluye el archivo pch.h
. Contiene una línea:
#include "pch.h"
A continuación, establecemos nuestro proyecto para que use el archivo PCH. Esto se hace en las propiedades del proyecto mediante C/C++>Encabezados precompilados y al establecer Encabezado precompilado en Use (/Yu) y Archivo de encabezado precompilado en pch.h.
La opción Encabezado precompilado está establecida en: Use (/Yu). El archivo de encabezado precompilado está establecido en pch.h.
Para usar el archivo PCH, lo incluimos como primera línea en los archivos de código fuente que usan winrtHeaders.h
. Debe venir antes de cualquier otro archivo de inclusión. O bien, por motivos de simplicidad, podríamos modificar las propiedades del proyecto para incluir el archivo pch.h
al principio de cada archivo de la solución estableciendo la propiedad del proyecto: C/C++>Avanzado>Archivo de inclusión forzado en pch.h
:
La opción Archivo de inclusión forzado está establecida en pch.h.
Dado que el archivo PCH incluye el archivo winrtHeaders.h
, podríamos quitar el archivo winrtHeaders.h
de todos los archivos que lo incluyen actualmente. No es estrictamente necesario porque el compilador detecta que el archivo winrtHeaders.h
ya está incluido y no lo vuelve a analizar. Algunos desarrolladores prefieren mantener las instrucciones #include
en el archivo de código fuente para mayor claridad o en el caso de que se refactorice el archivo PCH y ya no se incluya ese archivo de encabezado.
Probar los cambios
En primer lugar, limpiamos el proyecto para asegurarnos de que estamos comparando la compilación de los mismos archivos que antes. Para limpiar solo un proyecto, haga clic con el botón derecho en el proyecto en el Explorador de soluciones y elija Solo el proyecto>Limpiar solo <nombre del proyecto>.
Dado que este proyecto usa ahora un encabezado precompilado (PCH), no queremos medir el tiempo dedicado a crear el archivo PCH porque eso solo sucede una vez. Para ello, cargamos el archivo pch.cpp
y elegimos Ctrl+F7 para compilar solo ese archivo. También podríamos compilar este archivo mediante un clic con el botón derecho en el archivo pch.cpp
en el Explorador de soluciones y seleccionando Compile
.
Ahora, volvemos a ejecutar Build Insights en el Explorador de soluciones mediante un clic con el botón derecho en el proyecto y seleccionamos Solo el proyecto>Ejecutar Build Insights en la compilación. También puede hacer clic con el botón derecho en un proyecto en el Explorador de soluciones y elegir Ejecutar Build Insights>Compilar. No queremos recompilar esta vez porque eso recompilará el archivo PCH, algo que no queremos medir. Anteriormente, hemos limpiado el proyecto, lo que significa que una compilación normal compila todos los archivos del proyecto que queremos medir.
Cuando aparecen los archivos ETL, vemos que el tiempo de compilación pasó de 16,404 segundos a 6,615 segundos. Si escribe winrtHeaders.h
en el cuadro de filtro, no aparece nada. Esto se debe a que el tiempo dedicado al análisis ahora es insignificante, ya que el encabezado precompilado lo extrae.
En este ejemplo, se usan encabezados precompilados porque son una solución común antes de C++20. Sin embargo, a partir de C++20, hay otras formas, más rápidas y menos frágiles de incluir archivos de encabezado, como las unidades de encabezado y los módulos. Para obtener más información, consulte Comparación entre unidades de encabezado, módulos y encabezados precompilados.
Navegación entre las vistas
Hay algunas características de navegación para las vistas Archivos incluidos y Árbol de inclusión:
- Haga doble clic en un archivo (o pulse Entrar) en las vistas Archivos incluidos o Árbol de inclusión para abrir el código fuente de ese archivo.
- Haga clic con el botón derecho en un archivo de encabezado para buscar ese archivo en la otra vista. Por ejemplo, en la vista Archivos incluidos, haga clic con el botón derecho en el archivo
winrtHeaders.h
y elija Buscar en árbol de inclusión para verlo en la vista Árbol de inclusión.
O bien, puede hacer clic con el botón derecho en un archivo de la vista Árbol de inclusión para ir a él en la vista Archivos incluidos.
Sugerencias
- Puede ir a Archivo>Guardar como para guardar el archivo ETL en una ubicación más permanente y mantener un registro del tiempo de compilación. A continuación, puede compararlo con compilaciones futuras para ver si los cambios mejoran el tiempo de compilación.
- Si cierra accidentalmente la ventana de Build Insights, vuelva a abrirla buscando el archivo
<dateandtime>.etl
en la carpeta temporal. La variable de entorno de WindowsTEMP
proporciona la ruta de acceso de la carpeta de archivos temporales. - Para profundizar en los datos de Build Insights con Windows Performance Analyzer (WPA), haga clic en el botón Abrir en WPA en la parte inferior derecha de la ventana ETL.
- Arrastre las columnas para cambiar el orden de las columnas. Por ejemplo, puede que prefiera mover la columna Hora para que sea la primera columna. Para ocultar columnas, haga clic con el botón derecho en el encabezado de columna y deseleccione las columnas que no desea ver.
- Las vistas Archivos incluidos y Árbol de inclusión proporcionan un cuadro de filtro para encontrar un archivo de encabezado que le interese. Busca coincidencias parciales en el nombre que proporcione.
- A veces, el tiempo de análisis notificado para un archivo de encabezado es diferente en función del archivo que lo incluya. Esto se puede deber a la interacción de diferentes instrucciones
#define
que afectan a qué partes del encabezado estén expandidas, el almacenamiento en caché de archivos y otros factores del sistema. - Si olvida lo que intentan mostrarle las vistasArchivos incluidos o Árbol de inclusión, mantenga el puntero sobre la pestaña para ver una información sobre herramientas que describe la vista. Por ejemplo, si mantiene el puntero sobre la pestaña Árbol de inclusión, la información sobre herramientas indica: "Vista que muestra las estadísticas de cada archivo, donde los nodos secundarios son los archivos incluidos por el nodo primario".
- Puede ver casos (como en el archivo
Windows.h
) en los que la duración agregada de todos los tiempos de un archivo de encabezado es mayor que la duración de toda la compilación. Lo que sucede es que los encabezados se analizan en varios subprocesos al mismo tiempo. Si dos subprocesos invierten simultáneamente un segundo en analizar un archivo de encabezado, son 2 segundos de tiempo de compilación, aunque solo haya pasado un segundo de tiempo de reloj de pared. Para obtener más información, consulte Tiempo de responsabilidad del reloj de pared (WCTR).
Solución de problemas
- Si no aparece la ventana de Build Insights, realice una recompilación en lugar de una compilación. La ventana de Build Insights no aparece si realmente no se compila nada; que puede ser el caso si no se ha cambiado ningún archivo desde la última compilación.
- Si un archivo de encabezado que le interesa no aparece en las vistas Archivos incluidos ni Árbol de inclusión, no se ha compilado o su tiempo de compilación no es lo suficientemente significativo como para aparecer.
Consulte también
Creación de sugerencias y trucos de Insights
Comparación de unidades de encabezado, módulos y encabezados precompilados
Vídeo de Build Insights en Visual Studio: Pure Virtual C++ 2023
Compilaciones de C++ más rápidas y simplificadas: una nueva métrica de tiempo
Solución de problemas de inserción de funciones en tiempo de compilación
vcperf y Windows Analizador de rendimiento