Optimización de compilación de DIY Gradle

La guía definitiva para la optimización del rendimiento de la construcción de Gradle

Wilber Ccori huaman
Sep 7, 2018 · 10 min read
Hermosas construcciones. Fuente: https://gradle.com

Si eres como yo hace unos meses, has alcanzado un punto de quiebre. Te sientes algo parecido a la desesperación y no sabes qué hacer. Ya has probado todos los trucos clásicos, como jugar con argumentos de JVM y propiedades de Gradle, pero fue en vano.

Voy a mostrarle cómo mejorar realmente su rendimiento de construcción a través de análisis y pruebas rigurosas. Eso significa que no voy a tirarle al azar hacks para copiar — si esperabas una solución rápida, seca tus lágrimas y abróchate el cinturón de seguridad, porque estamos a punto de entrar en detalles mediante el análisis de tu construcción para encontrar los cuellos de botella.

Gradle 101

Para cualquier trabajo, creo que es importante comprender los fundamentos de sus herramientas. Como desarrollador de Android, la herramienta oficial es Gradle, que creo que viene con muchos conceptos erróneos. Para empezar, disparemos algunos de los comunes.

¿Cuál es la diferencia entre Android Studio y Gradle?

Esto es algo con lo que mucha gente lucha: equiparan Studio con Gradle. Si bien las dos herramientas se comunican entre sí (de ahí esos molestos diálogos de “Actualizar el complemento de Gradle”), tienen muy pocas similitudes. Uno es un editor elegante, el otro una herramienta de automatización.

Por ejemplo, a Gradle no le podría importar menos quién lo esté usando, demonios, podrías escribir código en Notepad ++ (¡ew!) O vim (☠️) y Gradle no sería más inteligente. Por ejemplo, todo podría estar subrayado en rojo en el IDE, pero funcionar ./gradlew assembleDebugfunciona bien. (Eso generalmente significa que tiene que eliminar la .idea/librariescarpeta para obligar a IntelliJ a actualizar sus índices por cierto).

En esencia, a Gradle le importan principalmente los archivos que engulle y los que escupe.

Consejo: si desea mejorar su comprensión de Gradle, migre a Kotlin DSL con esta práctica guía : podrá Ctrl + Bcontentarlo con todo su corazón.

Entonces, ¿cuál es el Android Gradle Plugin entonces?

Bueno, Gradle solo no hace nada en realidad. Si no se aplica ningún tipo de plugins, sólo obtendrá tareas integradas como help, tasksy buildEnvironment - los que no se van a construir sus ideas brillantes. Espera, ¡lo descubrí! Ese es el secreto para obtener versiones secundarias: ¡no construyas nada en realidad!

Bromas aparte, Gradle es una herramienta de automatización , no necesariamente una herramienta de compilación, simplemente opera en archivos de entrada para generar archivos de salida. El resto es lo que sea que hagas: solicitudes de red, ejecutar scripts de shell … cualquier cosa que puedas hacer desde la línea de comandos, puedes hacerlo desde Gradle.

Sin embargo, si vas a hacer algo, Gradle necesita saber qué es ese algo: ahí es donde entran los complementos: configuran tu compilación. Le dicen a Gradle qué unidades de trabajo o tareas están disponibles para que pueda ejecutar.

TL; DR: los complementos como el Android Gradle Plugin (AGP) le dicen a Gradle qué tareas están disponibles (paso de configuración) y luego las ejecuta (paso de ejecución).

Analizando su rendimiento de construcción actual

Con lo básico fuera del camino, vamos a optimizar sus scripts de compilación, configuración de complementos y ejecución de tareas. Ahora, ¿recuerdas cómo dije que esto sería un proceso complicado? Bueno, estás involucrado. 😁

Agregue el plugin de escaneo de compilación

Si bien Gradle incluye el plugin de análisis de compilación de forma predeterminada desde v2.0, querrá agregarlo manualmente para asegurarse de obtener la última versión y no tiene que estar de acuerdo con el ToS todo el tiempo.

Configuración simple del plugin de compilación de compilación

Reunir puntos de referencia básicos

Ejecutar ./gradlew helpdos veces y luego abrir el escaneo para la segundaejecución. Lo mismo para ./gradlew assembleDebug --rerun-tasksy ./gradlew assembleDebug.

Nota: estamos ejecutando la compilación dos veces para obtener la mejor aproximación de su rendimiento de compilación en el mundo real, incluido el almacenamiento en caché y otras optimizaciones.

Si usted es capaz de invertir el tiempo y esfuerzo adicional para intensificar su juego, referente a su construye con el Gradle de perfiles para obtener resultados mucho más precisos .

Ahora tiene tres puntos de referencia:

  1. Tiempo de configuración
  2. Limpiar el tiempo de ejecución
  3. Tiempo de ejecución incremental de compilación

Estos son los 3 escenarios que vamos a optimizar, comenzando con el tiempo de configuración.

Consejo: cada vez que cambie algo, vuelva a ejecutar la construcción para asegurarse de que dicho cambio tuvo el impacto que usted pensó que tenía.

Estadísticas del proyecto

Para darle una mejor idea de cómo su construcción debería funcionar en comparación con la mía, estas son las estadísticas de mi proyecto de prueba . (~ 15 módulos y ~ 20,000 líneas de código relacionado con Android al momento de escribir esto.)

Optimización general

Antes de entrar en los detalles, asegurémonos de tener los fundamentos abajo:

Consejo: ya que seguir el rastro de la última versión de X siempre es un problema, recomendaría usar un plugin de revisión de versión . TBH, no estoy seguro de por qué esto no es parte de Gradle por defecto.

Bonificación: si está utilizando una máquina antigua, hágase un favor y tírela. Al final del día, el hardware malo es igual a un rendimiento malo. La única solución es obtener una máquina nueva.

Optimizar el tiempo de configuración

Volviendo a los negocios, debe tener un escaneo de compilación que se parece a esto:

La pestaña Resumen

Al profundizar en la pestaña Rendimiento, encontrará todo tipo de detalles sobre su compilación:

La pestaña Visión general del rendimiento

Si su tiempo de configuración es superior a 10 segundos (y no tiene más de 300 módulos), algo está mal. De lo contrario, siempre que esté satisfecho con el tiempo de configuración, no dude en saltarse esta sección.

Nota: 4 segundos para configurar la compilación es realmente terrible, solo debería ser 1–2 segundos. Desafortunadamente, el complemento Kotlin resuelve incorrectamente las dependencias en el momento de la configuración .

Listo? Optimicemos el 💩 de ese tiempo de configuración.

Solicitudes de red de caché

Si está haciendo esto , desplácese hacia arriba para encontrar la mejor respuesta .

Compruebe la pestaña de actividad de la red y asegúrese de que no haya solicitudes:

Zero es mi héroe

No hagas operaciones costosas

Busque secuencias de comandos de cuello de botella que dominen su tiempo de configuración. Podría ser E / S de archivos, hash de procesamiento (Git) o ​​cualquier otra cosa inusualmente costosa. Básicamente, nunca deberías estar ejecutando cosas en el momento de la configuración .

Aparte de mi afterEvaluatebloqueo lento (causado por ese error de Kotlin que mencioné anteriormente), todo lo demás pasa la prueba con gran éxito:

Ejemplo de tiempo de configuración de script

No use las antiguas API de tarea

Gradle 4.9 salió con una nueva API que permite evitar la configuración de tareas . Al escribir estas líneas, AGP aún no es compatible con las nuevas API, pero la actualización está dirigida a v3.3 alpha 9.

Mientras tanto, asegúrate de no estar utilizando ninguna de las API que fuerzan la configuración de la tarea ; estas volverán a perseguirte más tarde.

Use las nuevas API de tareas

Por el contrario, asegúrese de utilizar cualquier tarea que cree en sus scripts de compilación en registerlugar de create(explícita o implícitamente).

Perfil de la construcción

Si has encontrado un cuello de botella pero no sabes de dónde viene el problema, es hora de perfilar tu construcción . Recomiendo usar JFR(necesitarás Oracle JDK y Linux para obtener gráficos de Flame):

$ ./gradle-profiler --profile jfr --project-dir "..." ayuda

Por ejemplo, puedes ver qué o.j.kotlin.g.i.AndroidSubpluginmalo es el complemento de Kotlin ( está obligando a Gradle a resolver los artefactos):

🔥

Y si no puede descubrir de quién es la falla, pero no cree que sea suya, el equipo de Gradle siempre está feliz de echar un vistazo a las instantáneas de creación de perfiles: performance@gradle.com .

Optimizar el tiempo de ejecución de compilación limpia

Para ser justos, realmente no he invertido en esta área porque no importa demasiado para mi desarrollo diario. Sin embargo, todavía hay algunos pasos básicos que puede seguir para asegurarse de que sus compilaciones completas no sean excesivamente lentas.

Tune JVM args

Ah sí, el truco clásico que todos los artículos de rendimiento de compilación de Gradle parecen mencionar. Resulta que a menos que estén mal configurados, no importan demasiado.

En esencia, su objetivo es minimizar la recolección de basura a la vez que mantiene saludable a su sistema en general. Entonces, si su tamaño de almacenamiento dinámico es demasiado pequeño, el GC se agitará constantemente. Demasiado grande, y comenzará a quedarse sin memoria del sistema para otras cosas como Chrome o IntelliJ. Como dijo Thanos, quieres que esté “perfectamente equilibrado, como todas las cosas deberían ser”. Menos todo el asesinato.

Ahora busque “Tiempo total de recolección de basura” y asegúrese de que no represente más del 5% de su compilación:

4/124 = 3,2%, se ve bien

Si es algo más que eso, dale al Daemon otro GB. Enjuague y repita.

Informe las tareas excesivamente lentas a las partes infractoras (y deshabilítelas si es posible)

Si una sola tarea domina tu construcción, algo está mal. Por ejemplo, el plugin Firebase Performance es notoriamente lento, algo que es dolorosamente obvio en la vista de línea de tiempo:

Ay

Cuando la tarea no es necesaria para sus compilaciones de desarrollo, no la ejecute. Puede hacerlo sin aplicar el complemento o deshabilitar la tarea en sí:

Ahora, tendrá una línea de tiempo uniformemente distribuida con las tareas más largas que con razón son las siguientes compileDebugKotlin:

Equilibrar

Aquí hay otro ejemplo: noté que las compilaciones installDebugeran excesivamente lentas debido a makeApkFromBundleForDebugeso, así que lo informé . El equipo de Studio encontró varios errores y optimizaciones de rendimiento perdidas.

Optimizar el tiempo de ejecución incremental de compilación

La importancia de las compilaciones incrementales solo es superada por el tiempo de configuración. Los ejecutará docenas (si no cientos) de veces al día, por lo que optimizarlos es la clave.

Asegúrese de que no se estén ejecutando tareas incrementales

Si no ha cambiado nada, no debería pasar nada cuando vuelva a ejecutar una compilación. El equipo de Studio está haciendo un gran trabajo en este frente, pero lamentablemente el equipo de Play Services todavía no ha hecho su GoogleServicesTaskincremental:

Vamos, estamos tan cerca!

Si hay tareas que no cree que deberían ejecutarse, haga clic en ellas para ver por qué se ha invalidado el caché. Lo más probable es que configure sus entradas de compilación no determinista y accidentalmente cada vez.

Minimice el uso del procesador de anotaciones (o use incrementos )

¿Estás usando módulos Glide solo para la RequestOptionssintaxis más bonita ? Pregúntese esto: ¿perder compilación incremental realmente lo vale? Para mi, la respuesta es no.

Modular su construcción

Sí, sé que esta también es una galleta difícil, pero al final dará resultado. No solo mejorará el rendimiento de la compilación, sino también la calidad del código impidiendo la separación clara de las preocupaciones entre los diferentes módulos de funciones.

Advertencia: el complemento de Kotlin aún no es compatible con la compilación,por lo que no verá grandes beneficios de rendimiento al editar módulos que no sean hojas al momento de escribir este artículo. Para ser justos, esto es culpa de Gradle .

Reemplace las apidependencias implementationsiempre que sea posible

Una vez que haya modularizado su compilación, querrá tener tantos módulos de hojas como sea posible. De lo contrario, sus hijos deben ser recompilados cada vez que cambien.

Próximos pasos

Si bien es posible que haya logrado aumentos de rendimiento hoy, eso no significa que no lo arruine nuevamente mañana. (Eso fue súper cínico de mi parte, lo siento 😊.) Comparta este artículo con sus colegas, asegúrese de que no estén infringiendo accidentalmente las reglas establecidas a lo largo de la guía.

También recomendaría aprovechar la versión de prueba gratuita de Gradle Enterprise para recopilar datos de algunas semanas y asegurarme de que todos los integrantes de su equipo obtengan el mejor rendimiento posible.

Bueno, eso es una envoltura. Espero haberle dado las herramientas para luchar contra los crecientes tiempos de construcción y maximizar su productividad. Siéntete libre de darme 👏 y Para conocer mas tecnologias pueden seguirme en mis redes sociales:

Facebook: https://web.facebook.com/wilbeDEV/

facebook: https://web.facebook.com/TechManiako/

Grupo_facebook: https://web.facebook.com/groups/166091130742535/

YouTube: https://www.youtube.com/c/WILBERCCORIDEVELOPER

Blogs: https://www.techmaniako.com/ED/

GitHub: https://github.com/wilberCcoriHuman

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade