¿Por qué la ejecución paralela en la compilación java toma crecimiento lineal en el tiempo
linux linux-kernel (1)
time javac Main.java --> 0m1.050s
time javac Main.java & javac Main.java --> 0m1.808s
time javac Main.java & javac Main.java & javac Main.java --> 0m2.690s
time javac Main.java & ... 8 time --> 0m8.309s
Cuando ejecutamos javac
comando javac
en paralelo y con cada aumento en javac
comando javac
se agrega ~1 sec
para que se complete todo el comando javac
.
¿Por qué hay un crecimiento lineal es el tiempo?
Es todo javac
proceso javac
mientras se ejecuta involucrado de algún tipo en locks
, si es así cómo superarlo para no tener un crecimiento lineal en el tiempo
PD: He intentado anteriormente en single core machine
double core machine
, la double core machine
4 core machine
todos mostraron el mismo comportamiento.
PS2: entorno RedHat7
, javac 1.7.0_79
El compilador de Java ya maneja la división de su trabajo entre los procesadores disponibles, incluso cuando solo compila un único archivo. Por lo tanto, ejecutar instancias de compilador separadas en paralelo no le dará las ganancias de rendimiento que espera.
Para demostrar esto, Main1.java
un programa java grande (1 millón de líneas, 10.000 métodos) en un solo archivo llamado Main1.java
. Luego hizo copias adicionales como Main2.java
a Main8.java
. Los tiempos de compilación son los siguientes:
Compilación de un solo archivo:
time javac Main1.java & --> (real) 11.6 sec
Ver este único archivo compilar en el top
revelado uso del procesador en su mayoría en el rango 200-400% (que indica el uso de CPU múltiple, 100% por CPU), con picos ocasionales en el rango 700% (el máximo en esta máquina es 800% ya que hay 8 procesadores).
A continuación, dos archivos al mismo tiempo:
time javac Main1.java & --> (real) 14.5 sec
time javac Main2.java & --> (real) 14.8 sec
Entonces solo tomó 14.8 segundos para compilar dos, cuando tomó 11.6 segundos para compilar uno. Eso definitivamente no es lineal. Estaba claro al mirar en la top
mientras estos se ejecutaban que cada compilador de java solo estaba aprovechando como máximo cuatro CPU a la vez (con picos ocasionales más altos). Debido a esto, los dos compiladores se encontraron con ocho CPU en su mayoría en paralelo.
A continuación, cuatro archivos al mismo tiempo:
time javac Main1.java & --> (real) 24.2 sec
time javac Main2.java & --> (real) 24.6 sec
time javac Main3.java & --> (real) 25.0 sec
time javac Main4.java & --> (real) 25.0 sec
De acuerdo, aquí hemos golpeado la pared. Ya no podemos paralelizar el compilador. Cuatro archivos tomaron 25 segundos cuando dos tomaron 14.8. Hay una pequeña optimización allí, pero es principalmente un aumento de tiempo lineal.
Finalmente, ocho simultáneamente:
time javac Main1.java & --> (real) 51.9 sec
time javac Main2.java & --> (real) 52.3 sec
time javac Main3.java & --> (real) 52.5 sec
time javac Main4.java & --> (real) 53.0 sec
time javac Main5.java & --> (real) 53.4 sec
time javac Main6.java & --> (real) 53.5 sec
time javac Main7.java & --> (real) 53.6 sec
time javac Main8.java & --> (real) 54.6 sec
Esto fue en realidad un poco peor que lineal, ya que ocho tomaron 54.6 segundos mientras que cuatro solo tomaron 25.0.
Así que creo que la conclusión de todo esto es tener fe en que el compilador hará un trabajo decente tratando de optimizar el trabajo que le das a través de los recursos de CPU disponibles, y que intentar agregar paralelización adicional a mano tendrá limitaciones (si corresponde) beneficio.
Editar:
Como referencia, hay dos entradas que encontré en la base de datos de errores de Oracle con respecto a la mejora de javac para aprovechar los múltiples procesadores:
- Error ID: JDK-6629150 - La queja original, esto fue marcado como un duplicado de:
- Id. De error: JDK-6713663 : sugiere la resolución y, en función de la "Fecha resuelta", parece que el soporte de multiprocesador en javac se agregó el 2008-06-12.