06 mayo 2009

GeneXus - Acelerando la compilación Java (Alternativa a SUN JDK)

El tiempo pasa y cada día la demanda de integración con otras aplicaciones externas es mayor.

Muchos tienen suerte y no necesitan utilizar librerías externas (o código Java embebido en programas), muchos con crear su aplicación 100% GeneXus y utilizar viejas versiones de Java les es suficiente (Anteriores a Java 1.5).

Sin embargo, hay casos en los que se requiere integrarse la aplicación contra implementaciones de terceros para que tu aplicación pueda funcionar, como por ejemplo; módulos de seguridad o interfaces de consulta o integración con otros sistemas (NO SOAP, NO GX).

En mi caso por ejemplo, tengo un producto con muchas dependencias a módulos (clases) implementados en múltiples versiones de Java (Desde cosas simples J 1.1 a cosas más avanzadas en Java 1.5+).

Actualmente estoy en un proceso de recompilación completa de la aplicación.

¿Que opciones tenía?

Quería velocidad en la compilación, recompilar una gran base de conocimiento no era algo de un día para el otro y necesitaba hacerlo de forma completa en el mínimo tiempo posible.

Los descartados:

Microsoft SDK for Java murió con la compatibilidad 1.1.
Jikes 1.22 murió con compatibilidad 1.4 (y algo de la 1.5)

Yo necesito Java 1.5+ !!!

No tenía otra que morir con el indiscutible ganador en Java, el compilador de SUN y su JDK.

Sin embargo el compilador de SUN siempre se lo vio como "Un compilador lento".

Investigando descubrí que no era el único en el mundo que se quejaba de su lentitud y de no tener alternativas.

Ahora bien, si bien no encontré ningún truco o pisadita para acelerar el JDK 1.6 de Sun, encontré que muchos elogiaban la diferencia en velocidad obtenida por los IDE's como el de Netbeans y Eclipse.

¿En donde estaba la diferencia?

En el fondo tanto NetBeans como Eclipse tienen que morir en el compilador de Sun (o eso yo pensaba), por lo que algo no me cerraba.
Investigando un poco más, llegué a lo que se denomina como JSR 199 (Java Compiler API).

A partir del momento en que Sun implementa en la máquina virtual de Java la posibilidad de compilación nativa (directamente por lenguaje), las cosas cambiaron.

A partir de ese momento dejó la puerta abierta a terceros a que sea posible implementarse sus propios compiladores (en realidad sus propias optimizaciones al momento de compilar, el que compila y genera el bytecode es la máquina virtual).

Tanto Eclipse como Netbeans hoy en día aprovechan estas funcionalidades para realizar las compilaciones directamente desde el IDE, independizándose del compilador binario, e implementando algoritmos mejorados que permitan compilar de la forma más optima posible.

Por el momento solamente conseguí conocer algunas implementaciones que aprovechan el JSR 199 a fondo:

- Netbean Compiler
Tengo entendido que sería posible utilizar los métodos y simular un javac de línea de comando.
Actualmente Netbeans no tiene publicada su api como para ser utilizado por terceros, hay que investigar un poquito más. Lo dejo en mi lista de cosas a investigar cuando tenga tiempo.

- Eclipse JDT Core Batch Compiler
Si, estos amigos de Eclipse vieron que la comunidad lo necesitaba, y lo liberaron como un módulo independiente del IDE de Eclipse. Gracias Eclipse!!!

- OpenJDK
Como aún no fue liberado oficialmente no le hice pruebas, pero en cuanto tenga tiempo lo probaré.
Existe la posibilidad de usarse en modo "Batch javac compatible" mediante la compilación de un módulo específico de compilación (que dará origen a un javac.jar, busquen en internet sobre Netbeans y javac.jar y encontrarán como crearlo desde los fuentes).
Lo que habría que probar es que si usa JSR 199 sería posible utilizar el Jar de OpenJDK con la máquina virtual de SUN 1.6. Habría que hacer la prueba también.

Como no he tenido tiempo para investigar el caso de Netbean o el de OpenJDK, se lo dejo a la comunidad para que vea si puede dar algún aporte o no.

Yo me voy a encargar de presentarles el caso que si pude probar.

¿Quien quiere compilar java 1.5+ a un velocidad mucho mejor que la del compilador de SUN?

Les presento a ...

Eclipse JDT Core Batch Compiler

Requisitos: Runtime de Java 1.6+ (SUN Java 6.0 por ejemplo o cualquier otra que implemente el JSR199)

Donde Bajarlo: Sitio o Directo

¿Como utilizarlo en GeneXus?

Para poder simular el compilador de Sun, deben de crearse un script de línea de comando que instancia el jar de eclipse y simule los parámetro del compilador original.

Ejemplo: ECJJavaC.cmd

@echo off
java -jar pathdeljar\ecj-3.4.2.jar -nowarn -source 1.5 -target 1.5 -cp "%CLASSPATH%" %1 %2 %3 %4 %5 %6 %7 %8 %9


En donde "pathdeljar" se debe de indicar el path en donde se encuentra el jar del compilador.

Los parámetros "source" y "target" deben de indicar la versión de Java origen (cuanto mas arrimada a la realidad mejor será la optimización) y destino que quieren generar, si no especifican nada se utilizará la última versión soportada por el runtime. (Si es java 6, utilizará 1.6)

Si por ejemplo nuestra aplicación es 100% implementada con GeneXus, sabemos que GeneXus es Java 1.1 compatible, por lo tanto en source le indicamos 1.3 (es lo mínimo que acepta).

Si queremos que sea compilado como por ejemplo en Java 1.5 compatible, en target le indicamos 1.5.

De esta forma pueden "jugar" con los orígenes y destinos que requieran, esto ayudará al compilador a detectar que técnicas de análisis de código debe de utilizar para lograr compilar sus fuentes.

Es posible compilar bytecode de cualquier versión de Java, por lo que pueden crear una versión de cada comando para cada versión destino y seleccionar en las producciones de cada versión el comando asociado a cada una de ellas.

Si quieren mayor información sobre los parámetros del compilador (o en la página de eclipse):
java -jar pathdeljar\ecj-3.4.2.jar -help

Los que me parecieron útiles
-time
Muestra el tiempo en que demora el compilador, muy buena info a nivel de líneas de código por segundo procesado y cantidad de clases generadas.
-verbose
Muestra internamente las lecturas y análisis de las dependencias, da muy buena información de donde saca las mismas (Cuando tienen mal el classpath esto les puede ayudar)
-log
Permite almacenar el resultado del procesamiento en un archivo log (En otro artículo les enseñaré como aprovechar este parámetro).

Ahora bien, lo que queda es ir a GeneXus y en la propiedad en donde se debe de indicar el compilador de SUN, se debe de apuntar al archivo de comando ECJJavaC.cmd que hemos creado.

Resultados

Las pruebas que hice me dieron que el compilador de Microsoft y Jikes siguen siendo indiscutiblemente los más rápidos (Para versiones viejas de Java).

Sin embargo utilizando el compilador de Eclipse frente al nativo de SUN logré mucho mejores resultados en los tiempos (En algunos casos hasta 4 veces más rápido que el de SUN).

Mejoras que pude detectar en el compilador de Eclipse frente al compilar de SUN.

- Tiempos en análisis de dependencias (Si tengo un classpath monumental con múltiples JAR's)
- Mejora en la utilización de recursos (Múltiples Cores, CPU, Memoria e IO)

Compatibilidad

Se hicieron pruebas con GeneXus 8.0, GeneXus 9.0 y GeneXus X, corroborando un correcto funcionamiento de la solución planteada.

Agradecimiento especiales a Matías Reina por sus ayuda en las pruebas del compilador en GeneXus 9.0 y X.

Les dejo un link en donde menciona un poco la historia del compilador de Eclipse (Para los curiosos, el compilador es una evolución del compilador de VisualAge Micro Edition - VAME).

Espero que les sea de utilidad.

6 comentarios:

Armin Bachmann dijo...

Hola David, quería comentar que en Evolution 1, especialmente con los últimos nightbuilds aplicados, cambiamos la forma de compilación y realmente las compilaciones ahora son mucho más rápidas. Hubo un cambio de orden en los tiempos. Has podido probar si con este método se mejora aún más en evolution?
Saludos y felicitaciones por el blog.

David Giordano dijo...

Hola Armin.

Estoy al tanto de las muchas mejoras que vienen realizando en los últimos nigth build's.

Sin embargo no he tenido mucho tiempo para probar estas últimas versiones, y por lo tanto, no he podido probar "la alternativa" sobre estas mismas.

Me gustaría saber si los tiempos de la EVO 1 NB SUN contra "la alternativa" realmente hace variar los tiempos de compilación.

¿Alguien se animaría a hacer esas pruebas y dejarme algún comentario sobre los resultados de las mismas?

Pablo Planinich dijo...

Hola David.

Sólo quería agregar a tu comentario la recomendación de utilizar Ant. Al menos en la GX 9.0 hemos encontrado grandes ventajas en cuanto a performance, especialmente en proyectos muy grandes.

Los tiempos son muy buenos: busca los .java que falte compilar, y los compila, sin pasar por GeneXus. Internamente puede usar el compilador de Eclipse. Eso (aparentemtente) me ayudó a sortear referencias a clases Gx sin package name.

La ventaja real del ant es que abre las puertas a muchas operaciones de deployment: sincronización, generación de wars, interfases de deploy con application servers, FTP, etc.

Por ejemplo, en un .xml configuramos para que se compilen y guarden las reorgs en archivos .jar (interfaseando con el full-cycle de GxTend).

La contra es la necesidad inicial de limpiar código generado con errores (por ejemplo, objetos de prueba que se generaron y luego se borran de las KBs, pero no del directorio de clases).

Felicitaciones por el Blog!

David Giordano dijo...

Muchas gracias Pablo!!

Lo de Ant es una buena idea, ya lo había evaluado, solo que necesitaba algo integrado con el proceso de compilación utilizado en GeneXus.

Con algunos "toques" de parámetros en el NMAKE y algunos otros en el compilador de Eclipse logré sortear todos los problemas sin necesidad de pasar por una solución por fuera.

Con respecto a la depuración, el proceso de generación y compilación que estoy implementando corre detrás de un proceso orquestado que controla, depura, genera y compila todo lo necesario, haciendo luego un deploy "inteligente" (porque no es solo un copy de todo lo tocado).

Con el Ant o MSBuild no podía hacer eso, siempre terminaba en crearme algo en .NET para enviar contra Ant o MSBuild, por lo que terminé pasando todo a .NET nativo.

En un principio evalué Ant, MSBuild, NAnt y si bien todos me daban herramientas llegué a la conclusión de que necesitaba herramientas adaptadas a las necesidades de GX.

Terminé implementando un sistemas propio de tareas al mejor estilo Ant/MSBuild que pueden ser ejecutadas por línea de comando o desde código .NET (Lo cual me permite usarlo tanto en Ant, NAnt, MSBuild o desde GX con Shell o propiamente desde línea de comando).

Con esto logré implementar herramientas que hoy ayudan en el ciclo de desarrollo , haciendo muchas tareas que antes eran interactivas de forma batch.

El día de mañana gran parte de la lógica será migrada a la X, seguramente por un lado creando MSBuild y colocando gran parte de la lógica tanto en el ID de GX como también en GXServer como Extensiones.

Actualmente lo que tengo implementado está para GX 8/9 compatible, y es de uso interno a la empresa.
Cuando termine con el proyecto veré de comenzar a adaptarlo a la X.

Por suerte los que desarrollamos herramientas sobre GeneXus, a partir de la X se nos viene haciendo mucho mas simple el camino, ya que Artech trabajó mucho en dar herramientas para interactuar tanto por dentro de GX como por fuera mediante los MSBuild Task.

Las mejoras que han realizado en la generación y compilación en la Evo 1 son sorprendentes, por lo que "batchisinar" con GeneXus X / EVO 1 ya es una tarea mucho más simple.

¿Este año tendremos alguna charla relacionada con GxTend en el encuentro?

Pablo Planinich dijo...

Esperamos ser un clásico del encuentro!

Sin lugar a dudas se están simplificando mucho las cosas de cara a futuro. GeneXus X es sin duda un entorno altamente extensible, lo que con el tiempo provocará que la comunidad como un todo genere y comparta más conocimiento. Esperemos entonces que proliferen los blogs. Todavía vengo aguantando el no empezar uno...

gicasuriaga dijo...

Oído de muy buena gente, openjdk anda muy bien con genexus