msbuild build-process build build-automation

Cómo disminuir los tiempos de MSBuild



msbuild rebuild (4)

Mi situación

En el proyecto C # en el que estoy trabajando ahora tenemos una solución bastante grande (más de 80 proyectos). Ahora, los tiempos de reconstrucción de más de 5 minutos se están convirtiendo en un gran problema al usar MSBuild desde Visual Studio 2008 .

En un análisis que hice la semana pasada, resultó que mi tiempo de construcción se gastó de la siguiente manera:

  1. Copiar archivos a los proyectos y volver a copiarlos a los proyectos que dependen de ellos (CopyToLocal), etc. (60%)

  2. Invocando un postbuild para descompilar / compilar. (20%)

  3. Haciendo la compilación real, etc. (20%)

Además de la salida ''normal'' del proyecto bin/debug salida de las carpetas también se copia en un directorio externo para configurar el programa principal del ''cargador''. La estructura principal del programa es un poco como esto:

/loader/bin/loader.exe /loader/plugin/plugin1/plugin1.dll /loader/plugin/plugin1/somedependency.dll

Lo que hice

En un intento por hacer que las cosas vayan un poco más rápido, pensé en lo siguiente:

  1. Copie todos los archivos en un directorio de un gran contenedor y no use CopyTolocal . No me gusta esto porque ya no podemos usar versiones diferentes de los mismos archivos DLL y mi directorio bin se está desordenando bastante.

  2. Use paralelismo (/ m) para MSBuild . Esto ayuda muy poco en tiempos de construcción.

  3. Intente reducir las dependencias entre proyectos, lo que siempre es bueno, por supuesto.

  4. Invertir en hardware. Encontré algunas investigaciones sobre unidades de estado sólido , pero esto no parece prometedor.

Mi pregunta

También noté que cuando realizo un cambio en un proyecto que está en la raíz de mi árbol de dependencias, todo se reconstruye. Incluso si el cambio fue solo en la parte ''privada'' y la interfaz del proyecto no cambió.

¿Utiliza MSBuild una marca de tiempo de proyectos dependientes para determinar si un proyecto necesita una reconstrucción?

¿Se puede cambiar esto a una condición diferente? Por ejemplo, ¿la suma de comprobación del archivo?

Aparte de esta sugerencia específica, seguramente apreciaría todas las sugerencias para que los tiempos de construcción sean más rápidos.


El tiempo de construcción de MSBuild es un problema multidimensional. La buena noticia de que es fácil de resolver:

A diferencia de la mayoría de los procesos que se ejecutan en la máquina de compilación, los procesos de compilación son conocidos por ser CPU, RAM y consumo de E / S. Una receta general para acelerar las compilaciones de MSBuild es "obtener la mejor máquina que el dinero puede comprar", en particular:

  1. CPU: al menos dos Intel 3.0 GHz Core 2 Duo.

  2. RAM - al menos 4 GB DDR3. Si se trata de un desarrollador y una máquina de compilación, un sistema operativo de 64 bits y 8 GB de RAM es una mejor opción.

  3. HDD: las opciones más rápidas son un RAID-1 de 3ware de gama alta con una batería integrada y un caché de escritura habilitado. Un SSD rápido puede ser otra opción a considerar.

  4. Red - tarjeta de 1 Gbit / s como mínimo.

Esta sencilla optimización de hardware puede acelerar tus MSBuilds 2-3 veces.


Estoy trabajando en más de 500 proyectos de aplicaciones C #. Los proyectos se compilan en paralelo y copylocal se establece en false. El tiempo de compilación es de aproximadamente 37 minutos sin pruebas unitarias ni cobertura de código. 13 min para construcción incremental sin ningún cambio en el código.

Si desactivo la compilación paralela y configuro copylocal en verdadero, el tiempo de compilación es de 1 h 40 min.

Tengo una configuración diferente para la compilación local, compilación de check-in cerrada y compilaciones de servidor con la fase de implementación (compilaciones nocturnas).

Aquí están mis experiencias:

  1. Copiar los archivos de salida en un directorio no es una buena idea si desea compilar sus proyectos en paralelo sin que CopyLocal esté configurado en falso. Mis ensamblajes a veces se bloqueaban cuando varios proyectos hacían referencia al mismo ensamblaje y MSBuild intentaba copiar esta referencia a la carpeta de salida al mismo tiempo. Esta solución fue muy útil para mí. Puse copylocal en falso para todas las referencias y el tamaño de mi directorio de compilación se redujo 10x (10 veces menos I / O). Tengo una configuración diferente para la compilación local y para la compilación del servidor. Configuración diferente para la compilación de check-in cerrada y para la compilación de implementación completa.
  2. Si habilito la compilación paralela, las compilaciones son más rápidas, mucho más rápidas. Si tiene un servidor de compilación robusto, su compilación /m:2 debería ser 2 veces más rápida que una compilación de /m:1 . No tiene nada que ver con las dependencias entre proyectos (si copylocal se establece en falso).
  3. Debería reducir las dependencias entre los proyectos si desea tener una construcción incremental rápida. No tiene ningún impacto en una compilación completa (copylocal false). El tiempo de compilación incremental depende de la ubicación del proyecto modificado en el árbol de compilación.

Sí, MSBuild usa una marca de tiempo de proyectos dependientes para determinar si un proyecto necesita una reconstrucción. Compara los archivos de entrada (archivos de código, conjuntos referenciados, archivos temporales, ...) marca de tiempo con el conjunto de salida. Si algo cambia, tu proyecto es recompilado. Intente reducir el número de dependencias entre proyectos para minimizar la recompilación. Si su cambio fue solo en la parte ''privada'' del proyecto, se modificará su conjunto de salida, se modificará la marca de tiempo del conjunto y también se reconstruirán todos los proyectos relacionados. No se puede hacer mucho con esto.

Ejecute su compilación dos veces con verbosidad de diagnóstico sin ningún cambio en su código y compruebe "Compatibilidad del objetivo de construcción" CoreCompile "completamente" como lo describí here . Puedes tener algo mal en tus archivos de proyecto y tus proyectos se compilan cada vez. Si no cambia nada, su registro de compilación no debe contener los registros "Destino de construcción" CoreCompile "completamente".

Nuestro servidor de compilación es una máquina virtual, no una pieza real de hardware. No es una buena idea usar una máquina virtual para un servidor de compilación, pero no fue mi decisión.

Si tiene varios GB de RAM, intente utilizar parte de ella como un disco duro en memoria. Tu construcción debería ser mucho más rápida :)

Las unidades SSD son sensibles a una alta E / S por día. Tiene un impacto en la garantía.

Espero que esto ayude a alguien ... ;)


Si tiene suficiente RAM y está utilizando Visual C ++ (no está seguro acerca de C #), podría acelerar el proceso copiando todo el directorio de inclusión y lib en una unidad de RAM.

También puede colocar los elementos de compilación temporales para que estén en la unidad de RAM. Por supuesto que necesitas una cantidad masiva de RAM. Una memoria RAM de 2 GB sería suficiente para las bibliotecas y los incluidos. Pero para los archivos temporales (* .obj, etc.) dependería del proyecto. Así que puede ser entre 1 y 4 GB extra o más.


También tenemos grandes soluciones. La compilación y compilación se trata de I / O.

Las unidades de estado sólido son muy prometedoras. Un compañero de trabajo puso una unidad de estado sólido en su computadora portátil y descubrió que ahora es mucho más rápido que su enorme caja de desarrollo principal. No tengo los detalles, pero él reclama muchas veces más rápido.

Hemos estado jugando con las carpetas de soluciones para agrupar partes del proyecto: esto facilita que los desarrolladores descarguen proyectos en los que no están trabajando .

/m rara vez ayuda con las compilaciones de depuración .NET . Hice una serie de pruebas sobre esto hace unas semanas y encontré pequeñas diferencias. Recomendaciones:

  • Debido a que mi compilación está restringida para E / S, el uso de / m: 2-4 hace que las depilaciones sean más lentas para mí.
  • Las versiones de lanzamiento suelen ser mucho más rápidas.
  • Análisis de código agrega mucho tiempo.

Imagen general: en realidad, la compilación es un costo bastante menor para mí, en comparación con las pruebas de unidad y de origen. En nuestro servidor de compilación, las pruebas de integración y el empaquetado son casi todo el tiempo. Para mi caja de desarrollo, programo un archivo por lotes que obtiene el origen, las compilaciones y las pruebas unitarias antes de ir al trabajo y mientras estoy almorzando. Suficientemente bueno.

En el servidor de compilación, es más complicado. Estamos pensando en configurar las versiones paralelas encadenadas de CruiseControl.NET en varias máquinas. Estamos usando VSTS build, pero es demasiado costoso (y consume mucho tiempo) escalar horizontalmente de esta manera.

Mis números para gente orientada al detalle. Configuraciones de la más lenta a la más rápida, ejecutando msbuild "bigsolution.sln" / target: clean - entre cada una.

  1. / m: 4, depuración con análisis de código 1:38
  2. / m: 1, depuración con análisis de código 1:30
  3. / m: 4, depuración sin análisis de código 1:30
  4. / m: 1, depuración sin análisis de código 1:30
  5. / m: 1, Lanzamiento con análisis de código: 1:30
  6. / m: 4, Lanzamiento con análisis de código: 1:05
  7. / m: 4, Lanzamiento sin análisis de código: 0:53

Tiempo de construcción sin reconstruir o limpiar: ~ 4-10 segundos