2008-09-27 16 views
22

Tenemos una aplicación C++ bastante grande que se compone de aproximadamente 60 proyectos en Visual Studio 2005. Actualmente, lleva 7 minutos enlazar en modo Release y me gustaría intentar reducir el tiempo ¿Hay algún consejo para mejorar el tiempo de enlace?Cómo mejorar el rendimiento del enlace para una gran aplicación C++ en VS2005

La mayoría de los proyectos se compilan en bibliotecas estáticas, esto hace que las pruebas sean más fáciles ya que cada una de ellas también tiene un conjunto de pruebas de unidades asociadas. Parece que el uso de bibliotecas estáticas evita que VS2005 use enlaces incrementales, por lo que incluso con la vinculación incremental activada, hace un enlace completo cada vez.

¿Usaría DLL para los subproyectos? Realmente no quiero ir a través de todos los encabezados y agregar macros para exportar los símbolos (incluso usando un script) pero si hiciera algo para reducir el tiempo de enlace de 7 minutos lo consideraré.

Por algún motivo, utilizar nmake desde la línea de comandos es un poco más rápido y vincular la misma aplicación en Linux (con GCC) es mucho más rápido.

  • IDE de Visual Studio 7 minutos
  • Visual C++ utilizando nmake desde la línea de comandos - 5 minutos
  • GCC en Linux 34 segundos
+0

¿Está usando muchas clases de plantilla? Tal vez están siendo instanciados varias veces, y esto no es necesario. –

+0

¿GCC está utilizando librerías estáticas o bibliotecas compartidas? –

+0

GCC está utilizando bibliotecas estáticas (.a). –

Respuesta

18

Si está utilizando el indicador /GL para habilitar la optimización de todo el programa (WPO) o el indicador /LTCG para habilitar la generación de código de tiempo de enlace, al apagarlos se mejorarán significativamente los tiempos de enlace, a expensas de algunas optimizaciones.

Además, si está utilizando el indicador /Z7 para poner símbolos de depuración en los archivos .obj, sus bibliotecas estáticas son probablemente enormes. Usar /Zi para crear archivos separados .pdb podría ayudar si evita que el vinculador lea todos los símbolos de depuración del disco. No estoy seguro de si realmente ayuda porque no lo he comparado.

+2

El distintivo/Z7 se configuró en varias bibliotecas. Cambiar a/Zi hizo una gran diferencia. El tiempo de enlace ahora es de 2 minutos. Todavía me gustaría obtenerlo más rápido, así que tal vez vea usar DLL. Pero esto ayudó mucho. Gracias. –

1

60 libs Para enlazar suena como una feria pocos. Esta puede ser una medida extrema, pero puede acelerar radicalmente las cosas. Cree una nueva solución, con algunos proyectos, y agregue todo el origen de sus proyectos existentes a estos. Luego compártalas y únelas en su lugar, y solo guarde las pequeñas para la prueba.

1

Obtenga una computadora más rápida con múltiples procesadores y habilite compilaciones paralelas (esto podría estar activado por defecto). Para permitir la mayor cantidad de paralismo, asegúrese de que las dependencias de su proyecto sean correctas y no tenga dependencias innecesarias.

+0

La compilación paralela funciona para compilar pero no para vincular. No creo que el enlazador VC2005 pueda usar más de un procesador. –

+1

Visual Studio admite varios subprocesos para cada proyecto, no múltiples subprocesos dentro de un único proyecto. El enlace solo usa 1 hilo. – gbjbaanb

+1

Con VC2005, el modificador/MP permite varios subprocesos para compilar en un único proyecto. Pero enlazar todavía solo usa un hilo. Esto funcionó en VC2005, pero solo se presentó oficialmente en VC2008, creo. –

2

No creo que la conversión a archivos DLL sea útil. Puede intentar buscar opciones relacionadas con la optimización y desactivarlas. El enlazador puede estar pasando mucho tiempo buscando en las librerías un código redundante que puede eliminar. Tu aplicación puede terminar más grande o más lenta, pero eso puede no ser un problema para ti.

5

En general, usar DLL en lugar de bibliotecas estáticas mejorará un poco los tiempos de enlace.

4

Eche un vistazo a Incredibuild por Xoreax. Su compilación distribuida redujo drásticamente nuestros tiempos completos de construcción/enlace de aproximadamente 40 minutos a 8 minutos.

Además, este producto tiene una característica que llaman Incredilink que debería ayudarle a obtener enlaces incrementales que funcionen incluso con bibliotecas vinculadas estáticamente.

2

Varias personas han informado (y yo mismo lo he notado) que la modificación de un archivo en una biblioteca enlazada estáticamente deshabilitará el enlace incremental para toda la solución; esto parece ser lo que estás viendo. Consulte los comentarios here y here para obtener más información al respecto.

Una solución consiste en utilizar el complemento Fast Solution Build. Esto puede implicar hacer algunos cambios en su espacio de trabajo, pero la recompensa es definitivamente vale la pena. Para una solución comercial, use Xoreax's Incredibuild, que básicamente incorpora esta misma tecnología pero agrega otras características también.Me disculpo si sueno como un vendedor de Incredibuild. Solo soy un cliente muy satisfecho.

+0

¿Fast Solution Build funciona con VS2005? Solo puedo ver referencias a Visual Studio.NET –

+0

Esa es una buena pregunta, no estoy seguro. Apuesto a que si le enviaste un correo electrónico al desarrollador, te lo hará saber. –

+1

VS2005 y superior tiene una opción de vinculador llamada "Usar entrada de dependencia de biblioteca". Hará que el vinculador incluya los archivos obj de las bibliotecas estáticas en lugar del archivo lib de salida de la biblioteca estática. Esto habilitará la vinculación incremental incluso si se utilizan bibliotecas estáticas. –

1

Si realmente está hablando de los tiempos de enlace, entonces cosas como la construcción rápida de soluciones y Xoreax en realidad no ayudarán mucho (a excepción de Incredilink, que podría). Suponiendo que está midiendo realmente el inicio del enlace al final del enlace, le sugiero que el número de libs que tiene es el problema.

La fase de enlace está, al menos inicialmente, ligada a IO en la carga de todos los archivos de objeto y lib. Es posible que se encuentre en una situación en la que tenga 60 bibliotecas junto con el proyecto principal de una gran cantidad de archivos .obj. Sospecho que simplemente podría estar viendo, al menos en parte, la lentitud típica de las ventanas al cargar todas esas bibliotecas y archivos .obj.

Puede probar esto fácilmente. Tome todos esos archivos lib y cree un solo archivo lib solo como una prueba. En lugar de vincular con 60 de ellos, enlace con uno y vea a dónde va su tiempo. Eso puede ser interesante.

NTFS es notoriamente lento. No debería ser 7m contra 32 segundos en Linux lento, pero podría ser parte del problema. Usar DLL ayudará pero sufrirá el tiempo de inicio de la aplicación, aunque eso no será tan temprano como antes. Confío en que no tendrá 7 meses de inicio de aplicación.

+1

La compilación de soluciones rápidas ayuda con los tiempos de enlace; efectivamente permite el enlace incremental en lugar de enlaces completos cuando se modifican las bibliotecas estáticas. Ver mis tiempos de enlace pasan de 7 minutos a 15 segundos, mientras enlaza ~ 40 bibliotecas, me demuestra que este es el problema principal, no el archivo de E/S. –

+0

interesante. Obviamente no sé lo suficiente sobre cómo funciona. Tendré que verificarlo. Gracias por el seguimiento. – Mark

2

He tenido problemas similares al vincular aplicaciones grandes con Visual C++ antes. En mi caso, simplemente no tenía suficiente RAM libre y el exceso de paginación en el disco ralentizaba el proceso de enlace hasta detenerlo. Duplicar mi RAM de 1GB a 2GB hizo una mejora dramática. ¿Cuánto está funcionando su caja de desarrollo?

+1

Es una máquina Intel Core 2 Duo con 3 GB de RAM. –

1

puede intentar mirar esto: http://msdn.microsoft.com/en-us/library/9h3z1a69.aspx

Básicamente, puede ejecutar proyecto se basa en paralelo si usted tiene varios núcleos.

+1

Esto acelerará la compilación inicial a medida que los proyectos se crean en paralelo. Además, existe el conmutador MP no documentado que permite que un solo proyecto utilice múltiples núcleos. Pero la pregunta era sobre el tiempo de enlace de un solo proyecto y no se admite el enlace multi-CPU. –

2

Me acabo de enterar de que habíamos definido accidentalmente una gran tabla de cadenas en un archivo de cabecera que se incluyó en casi todas las lib (estáticas). (Estoy hablando de un gran proyecto de C++). Cuando el enlazador creó el EXE, parece que la unificación de la tabla (solo hay una sola terminando en el EXE) o el análisis de las librerías tomó para siempre. Poner la tabla en un archivo separado de C++ tomó un par de minutos del enlace en una máquina relativamente lenta.

Lamentablemente, no sé cómo encontrar cosas así por casualidad.

2

Para compilaciones de depuración, se pueden usar enlaces incrementales, lo que puede mejorar mucho los tiempos de enlace.

Lamentablemente, existen ciertos inconvenientes, y el VS2005 no lo avisará.

  • Si se utilizan bibliotecas estáticas, el enlace incremental no funcionará si se modifica una parte del archivo para la biblioteca estática.La solución es establecer la opción del vinculador "Utilizar entradas de dependencia de biblioteca" en "Sí" (Esto es lo mismo que Creación de solución rápida en VS2003)

  • Si utiliza pragma-comment-lib para incluir la lib de una DLL, y especifica una ruta relativa en lugar de solo la lib, luego el enlace incremental dejará de funcionar. La solución es especificar solo la lib y usar la opción de enlace LIBPATH para agregar una ruta de acceso adicional.

  • Algunas veces el archivo .ilk se dañará (crecerá más allá de 200 MByte) y de repente el enlazador incremental tarda más de 10 veces el tiempo normal. Algunas veces se quejará si el archivo .ilk está dañado, pero generalmente primero después de varios minutos. La solución para mí fue configurar el siguiente comando para "Build Event" -> "Pre-Link Event"

    para %% f in ($ (IntDir) *. Ilk) do (si "%% ~ zf "GTR "200000000"(del %% f))

7

ver a mi sugerencia formulada en Microsoft: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=511300

Usted debe votar por ella! Aquí está mi último comentario al respecto:

Sí, estamos usando enlaces incrementales para construir la mayoría de nuestros proyectos. Para los proyectos más grandes, es inútil. De hecho, lleva más tiempo vincular esos proyectos con enlaces incrementales (2min50 comparado con 2min44). Observamos que no funciona cuando el tamaño de los archivos ILK es grande (nuestro proyecto más grande genera una suerte de 262144 KB en la victoria 32).

Bellow, que lista otras cosas que tratamos de reducir el tiempo de enlace:

  • explícita de instancias de plantilla para reducir la hinchazón de código. Pequeña ganancia.
  • IncrediLink (IncrediBuild da ganancia interesante para la compilación pero casi no gana nada para el enlace).
  • Elimina la información de depuración para bibliotecas que rara vez se depuran (buena ganancia).
  • Eliminar el archivo PDB en «Evento de preconstrucción» (curiosamente da una ganancia interesante, por ejemplo: 2min44 en vez de 3min34).
  • Convierte muchas bibliotecas estáticas a DLL. Ganancia importante
  • Trabajar con una computadora equipada con mucha RAM para maximizar la memoria caché de disco. La mayor ganancia
  • obj grande contra obj pequeño. Ninguna diferencia.
  • Cambiar las opciones del proyecto (/ Ob1,/INCREMENTAL, Habilitar plegado de COMDAT, manifiesto de incorporación, etc.). Algunos dan ganancia interesante otros no. Intentamos maximizar continuamente nuestra configuración.
  • Maximizar la vinculación interna vs Enlace externo. Es una buena práctica de programación.
  • Separe el componente de software tanto como podamos. Puede trabajar en la prueba unitaria que enlace rápido. Pero aún tenemos que integrar las cosas juntas, tenemos código heredado y trabajamos con componentes de terceros.
  • Utilice el conmutador de vinculador secreto/expectedoutputsize: 120000000. Pequeña ganancia.

Tenga en cuenta que para toda nuestra experimentación, medimos meticulosamente el tiempo de enlace. El tiempo de enlace lento implica un serio costo en productividad. Cuando implemente un algoritmo complejo o rastree un error difícil, querrá iterar rápidamente esta secuencia: modifique algún código, enlace, seguimiento de depuración, modifique algún código, enlace, etc.

Otro punto para optimizar el tiempo de enlace es el impacto que tiene en nuestro ciclo de integración continua. Tenemos muchas aplicaciones que comparten código común y estamos ejecutando una integración continua en él. El tiempo de enlace de todas nuestras aplicaciones tomó la mitad del tiempo de ciclo (15 minutos) ...

En el hilo https://blogs.msdn.microsoft.com/vcblog/2009/09/10/linker-throughput/, se hicieron algunas sugerencias interesantes para mejorar el tiempo de enlace. En una computadora de 64 bits, ¿por qué no ofrecer una opción para trabajar con archivos completamente en RAM?

De nuevo, cualquier sugerencia que pueda ayudarnos a reducir el tiempo de enlace es bienvenida.

1

He resuelto mi problema de enlace y lo comparto con todos ustedes.

El tiempo de enlace de mi proyecto fue de 7 min con/Incremental: sin enlaces (tiempo de enlace 7min).

Fue 15 min con/Incremental, (tiempo de enlace 7min, tiempo de manifestación embebido 7min). Así que apago lo inremental.

He encontrado dependencias adicionales tiene a.lib Y también ignore las bibliotecas específicas.

Así que lo elimino de Ignorar bibliotecas específicas encienda el/incremental. el primer tiempo de enlace necesita 5 minutos pero el tiempo manifiesto manifiesto no tiene ninguno.

No sé por qué, pero el enlace incremental ha funcionado.

Revertí todo el código del proyecto, por lo que pude encontrar el problema por lib. Si haces todo lo anterior, puedes probar mi método. ¡Buena suerte!

1

Paso 1 en C++ la reducción del tiempo de compilación es más memoria. Después de cambiar de 4GB a 12GB, vi que mi tiempo de enlace-todos-los proyectos caía por un precipicio: de 5:50 a 1:15.

Cuestiones relacionadas