Compilación de código en paralelo usando make

Compilación de código en paralelo usando make

Quien le pregunte cómo construir el software correctamente se le ocurrirá a Make como una de las respuestas. En los sistemas GNU/Linux, GNU Make [1] es la versión de código abierto de la marca original que se lanzó hace más de 40 años, en 1976. Hacer obras con un archivo MakFile: un archivo de texto sin formato estructurado con ese nombre que se puede describir mejor como el manual de construcción para el proceso de construcción de software. MakeFile contiene una serie de etiquetas (llamadas objetivos) y las instrucciones específicas debían ejecutarse para construir cada objetivo.

Simplemente hablando, hacer es una herramienta de compilación. Sigue la receta de tareas del makfile. Le permite repetir los pasos de manera automatizada en lugar de escribirlos en una terminal (y probablemente comete errores mientras escribe).

El listado 1 muestra un ejemplo de archivo con los dos objetivos "E1" y "E2", así como los dos objetivos especiales "All" y "Limpie."Ejecutar" Make E1 "ejecuta las instrucciones para el objetivo" E1 "y crea el archivo vacío uno. Ejecutar "Make E2" hace lo mismo para el objetivo "E2" y crea el archivo vacío dos. La llamada de "hacer todo" ejecuta las instrucciones para el objetivo E1 primero y E2 a continuación. Para eliminar los archivos creados anteriormente uno y dos, simplemente ejecute la llamada "Hacer limpio."

Listado 1

Todos: E1 E2
E1:
tocar uno
E2:
tocar dos
limpio:
RM uno dos

Running Make

El caso común es que escribe su archivo Make y luego solo ejecuta el comando "hacer" o "hacer todo" para construir el software y sus componentes. Todos los objetivos están integrados en orden en serie y sin paralelización. El tiempo total de construcción es la suma de tiempo que se requiere para construir cada objetivo.

Este enfoque funciona bien para pequeños proyectos, pero tarda mucho en proyectos medianos y más grandes. Este enfoque ya no está actualizado ya que la mayoría de las CPU actuales están equipadas con más de un núcleo y permiten la ejecución de más de un proceso a la vez. Con estas ideas en mente, observamos si el proceso de construcción puede ser paralelo. El objetivo es simplemente reducir el tiempo de construcción.

Realizar mejoras

Hay algunas opciones que tenemos - 1) Simplifique el código, 2) distribuya las tareas únicas en diferentes nodos informáticos, cree el código allí y recopile el resultado de allí, 3) cree el código en paralelo en una sola máquina, y 4) Combine las opciones 2 y 3.

La opción 1) no siempre es fácil. Requiere la voluntad de analizar el tiempo de ejecución del algoritmo implementado y el conocimiento sobre el compilador, i.mi., ¿Cómo traduce el compilador las instrucciones en el lenguaje de programación a las instrucciones del procesador?.

La opción 2) requiere acceso a otros nodos informáticos, por ejemplo, nodos informáticos dedicados, máquinas no utilizadas o menos utilizadas, máquinas virtuales de servicios en la nube como AWS o energía informática alquilada de servicios como LoadTeam [5]. En realidad, este enfoque se utiliza para crear paquetes de software. Debian GNU/Linux usa la llamada Red Autobuilder [17], y Redhat/Feders usa Koji [18]. Google llama a su sistema BuildRabbit y se explica perfectamente en la charla de Aysylu Greenberg [16]. DISTCC [2] es un llamado compilador C distribuido que le permite compilar el código en diferentes nodos en paralelo y configurar su propio sistema de compilación.

La opción 3 usa la paralelización a nivel local. Esta puede ser la opción con la mejor relación costo-beneficio para usted, ya que no requiere hardware adicional como en la opción 2. El requisito de ejecutar Make en paralelo es agregar la opción -j en la llamada (abreviatura de -jobs). Esto especifica el número de trabajos que se ejecutan al mismo tiempo. La lista a continuación solicita hacer para ejecutar 4 trabajos en paralelo:

Listado 2

$ make --jobs = 4

Según la ley de Amdahl [23], esto reducirá el tiempo de construcción en casi un 50%. Tenga en cuenta que este enfoque funciona bien si los objetivos individuales no dependen unos de otros; Por ejemplo, la salida del objetivo 5 no es necesaria para construir el objetivo 3.

Sin embargo, existe un efecto secundario: la salida de los mensajes de estado para cada objetivo de marca parece arbitrario, y estos ya no pueden asignarse claramente a un objetivo. El orden de salida depende del orden real de la ejecución del trabajo.

Definir hacer orden de ejecución

¿Hay declaraciones que ayuden a comprender qué objetivos dependen unos de otros?? Sí! El ejemplo de MakeFile en el Listado 3 dice esto:

* Para construir el objetivo "todo", ejecute las instrucciones para E1, E2 y E3

* El objetivo E2 requiere que el objetivo E3 se construya antes

Esto significa que los objetivos E1 y E3 se pueden construir en paralelo, primero, luego E2 sigue tan pronto como se complete la construcción de E3, finalmente.

Listado 3

Todos: E1 E2 E3
E1:
tocar uno
E2: E3
tocar dos
E3:
tocar tres
limpio:
RM uno dos tres

Visualizar las dependencias de hacer

La herramienta inteligente Make2Graph de MakeFile2Graph [19] Visualiza las dependencias de Make como un gráfico acíclico dirigido. Esto ayuda a comprender cómo dependen los diferentes objetivos entre sí. Make2Graph emite descripciones de gráficos en formato DOT que puede transformar en una imagen PNG utilizando el comando DOT del proyecto GraphViz [22]. La llamada es la siguiente:

Listado 4

$ Make All -Bnd | make2graph | gráfico DOT -TPNG -O.png

En primer lugar, se llama a Make con el objetivo "todos" seguido de las opciones "-B" para construir incondicionalmente todos los objetivos, "-n" (abreviatura de "-secado") para fingir ejecutar las instrucciones por objetivo y " -d "(" -debug ") para mostrar información de depuración. La salida se tuvo en cuenta para make2graph que tiene su salida a puntos que genera el gráfico de archivo de imagen.PNG en formato PNG.


El gráfico de dependencia de compilación para el Listado 3

Más compiladores y sistemas de construcción

Como ya se explicó anteriormente, Make se desarrolló hace más de cuatro décadas. A lo largo de los años, la ejecución de empleos en paralelo se ha vuelto cada vez más importante, y el número de compiladores y sistemas de construcción especialmente diseñados para lograr un mayor nivel de paralelización desde entonces ha crecido desde entonces. La lista de herramientas incluye estas:

  • Bazel [20]
  • CMake [4]: ​​Abreviatura de la planificación cruzada, crea y crea archivos de descripción que luego se usan por Make
  • distma [12]
  • Sistema de fabricación distribuido (DMS) [10] (parece estar muerto)
  • dmake [13]
  • LSF hace [15]
  • Apache maven
  • Mesón
  • Ninja Build
  • Nmake [6]: Hacer para Microsoft Visual Studio
  • Pydoit [8]
  • Qmake [11]
  • rehacer [14]
  • Scons [7]
  • WAF [9]

La mayoría de ellos han sido diseñados con la paralelización en mente y ofrecen un mejor resultado con respecto al tiempo de construcción que hacer.

Conclusión

Como ha visto, vale la pena pensar en las construcciones paralelas, ya que reduce significativamente el tiempo de construcción hasta cierto nivel. Aún así, no es fácil de lograr y viene con ciertas dificultades [3]. Se recomienda analizar tanto su código como su ruta de compilación antes de pasar a compilaciones paralelas.

Enlaces y referencias

  • [1] GNU Make Manual: Ejecución paralela, https: // www.ñu.org/software/make/manual/html_node/parallel.html
  • [2] Distcc: https: // github.com/DISTCC/DISTCC
  • [3] John Graham-Cumming: Las dificultades y los beneficios de GNU hacen paralelización, https: // www.cmcrossroads.com/Artículo/Pitfalls-and-Benefits-Gnu-Make-Paralelización
  • [4] Cmake, https: // cmake.org/
  • [5] LoadTeam, https: // www.diámetro de carga.com/
  • [6] nmake, https: // documentos.Microsoft.com/en-us/cpp/build/reference/nmake-reference?Ver = MSVC-160
  • [7] Scons, https: // www.escondites.org/
  • [8] Pydoit, https: // pydoit.org/
  • [9] WAF, https: // gitlab.com/ita1024/waf/
  • [10] Sistema de marca distribuido (DMS), http: // www.nongnu.org/dms/índice.html
  • [11] Qmake, https: // doc.QT.IO/QT-5/QMake-Manual.html
  • [12] Distmake, https: // SourceForge.net/proyectos/distma/
  • [13] dmake, https: // documentos.oráculo.com/cd/e19422-01/819-3697/dmake.html
  • [14] rehacer, https: // rehacer.readthedocs.io/en/Último/
  • [15] LSF Make, http: // sunray2.MIT.edu/kits/plataforma-lsf/7.0.6/1/guías/kit_lsf_guide_source/print/lsf_make.pdf
  • [16] Aysylu Greenberg: Construyendo un sistema de construcción distribuido en Google Scale, Goto Conference 2016, https: // gotocon.com/dl/goto-chicago-2016/slides/ayylugreenberg_buildingadistributedbuildsystematgooglescale.pdf
  • [17] Debian Build System, Autobuilder Network, https: // www.debian.org/Devel/buildd/índice.interno.html
  • [18] Koji - Sistema de construcción y seguimiento de RPM, https: // PAGURE.io/koji/
  • [19] Makefile2Graph, https: // github.com/lindenb/makefile2graph
  • [20] Bazel, https: // bazel.construir/
  • [21] Tutorial de Makefile, https: // Makefiletutorial.com/
  • [22] GraphViz, http: // www.graphviz.organizar
  • [23] La ley de Amdahl, Wikipedia, https: // en.Wikipedia.org/wiki/amdahl%27S_LAW