Cómo mejorar el rendimiento de una app con los perfiles de Baseline

1. Antes de comenzar

En este codelab, se explica cómo generar perfiles de Baseline para optimizar el rendimiento de tu aplicación y verificar los beneficios de usar dichos perfiles.

Requisitos

Actividades

  • Configuración del proyecto para que use generadores de perfiles de Baseline.
  • Generación de perfiles de Baseline para optimizar el inicio de la app y el rendimiento del desplazamiento.
  • Verificación de los aumentos del rendimiento con la biblioteca de Jetpack Macrobenchmark.

Qué aprenderás

  • Perfiles de Baseline y cómo pueden ayudarte a mejorar el rendimiento de la app.
  • Cómo generar perfiles de Baseline.
  • Mejoras de rendimiento de los perfiles de Baseline.

2. Cómo prepararte

Para comenzar, clona el repositorio de GitHub desde la línea de comandos usando el siguiente comando:

$ git clone https://github.com/android/codelab-android-performance.git

Como alternativa, puedes descargar dos archivos ZIP:

Abre un proyecto en Android Studio

  1. En la ventana Welcome to Android Studio, selecciona 61d0a4432ef6d396.png Open an Existing Project.
  2. Selecciona la carpeta [Download Location]/codelab-android-performance/baseline-profiles. Asegúrate de seleccionar el directorio que contiene baseline-profiles.
  3. Cuando Android Studio importe el proyecto, asegúrate de poder ejecutar el módulo app para compilar la aplicación de ejemplo con la que trabajarás más adelante.

App de ejemplo

En este codelab, trabajarás con la aplicación de ejemplo JetSnack. Es una app virtual de pedidos de bocadillos que usa Jetpack Compose.

Para medir el rendimiento de la aplicación, tienes que comprender la estructura de la IU y el comportamiento de la app de modo que puedas acceder a los elementos de la IU desde las comparativas. Ejecuta la app y haz algunos pedidos de bocadillos para familiarizarte con las pantallas básicas. No es necesario que conozcas los detalles de la arquitectura de la app.

23633b02ac7ce1bc.png

3. ¿Qué son los perfiles de Baseline?

Los perfiles de Baseline mejoran la velocidad de ejecución del código en aproximadamente un 30% desde el primer lanzamiento, ya que evitan la interpretación y los pasos de compilación just-in-time (JIT) para las instrucciones de código incluidas. Cuando se envía un perfil de Baseline a una app o biblioteca, Android Runtime (ART) puede optimizar las instrucciones de código incluidas a través de la compilación anticipada (AOT), lo que brinda mejoras de rendimiento para cada usuario nuevo y con cada actualización de la app. Esta optimización guiada por perfil (PGO) permite que las apps optimicen el inicio, reduzcan los bloqueos de interacción y mejoren el rendimiento general del entorno de ejecución para los usuarios finales desde el primer lanzamiento.

Con un perfil de Baseline, todas las interacciones del usuario (como el inicio de la app, la navegación entre pantallas o el desplazamiento por el contenido) son más fluidas desde la primera vez que se ejecutan. El aumento de la velocidad y la capacidad de respuesta de una app genera más usuarios activos por día y un promedio más alto de la tasa de visitas recurrentes.

Los perfiles de Baseline ayudan a guiar la optimización más allá del inicio de la app, ya que proporcionan interacciones comunes del usuario que mejoran el tiempo de ejecución de la app desde el primer lanzamiento. La compilación anticipada guiada no depende de los dispositivos de los usuarios y se puede realizar una vez por versión en una máquina de desarrollo en lugar de un dispositivo móvil. Cuando se envían versiones con un perfil de Baseline, las optimizaciones de las apps están disponibles mucho más rápido que si solo se basaran en los perfiles de Cloud.

Si no se usa un perfil de Baseline, todo el código de la app se ejecuta con compilación JIT en la memoria después de que se interpreta o en un archivo odex en segundo plano cuando el dispositivo está inactivo. La experiencia de los usuarios puede no ser óptima si se ejecuta una app después de instalarla o actualizarla por primera vez antes de la optimización de las nuevas rutas de acceso.

4. Configura el módulo de generación de perfiles de Baseline

Puedes generar perfiles de Baseline con una clase de prueba de instrumentación. Esto requiere que agregues un nuevo módulo de Gradle al proyecto. La forma más fácil de hacerlo es con el asistente de módulos de Android Studio Hedgehog o versiones más recientes.

Abre la ventana "New Module" del asistente. Para ello, haz clic con el botón derecho en el proyecto o módulo que encontrarás en el panel Project y selecciona New > Module.

232b04efef485e9c.png

En la ventana que se abrió, selecciona Baseline Profile Generator en el panel Templates.

b191fe07969e8c26.png

Además de los parámetros de siempre, como el nombre del módulo, el nombre del paquete, el idioma o el idioma de configuración de compilación, existen dos parámetros de entrada que no son los normales para un módulo nuevo: Target application y Use Gradle Managed Device.

La app de destino es el módulo de la app para el que se generarán los perfiles de Baseline. Si tienes más de un módulo de app en el proyecto, selecciona para cuál deseas que se ejecuten los generadores.

En la casilla de verificación del Use Gradle Managed Device se configura el módulo en el que se ejecutarán los generadores de perfiles de Baseline con emuladores de Android administrados automáticamente. Para obtener más información sobre los dispositivos administrados por Gradle, consulta el artículo Ajusta tus pruebas con dispositivos administrados por Gradle. Si se desmarca la casilla, los generadores usarán cualquiera de los dispositivos conectados.

Una vez que hayas definido todos los parámetros del módulo nuevo, haz clic en Finish para continuar con la creación del módulo.

Cambios realizados por el asistente de módulos

El asistente de módulos realiza varios cambios en tu proyecto.

Se agrega un módulo de Gradle llamado baselineprofile o el nombre que hayas seleccionado en el asistente.

Este módulo usa el complemento com.android.test, que le indica a Gradle que no lo incluya en tu app, de modo que solo pueda contener código de prueba o comparativas. También usa el complemento androidx.baselineprofile, que permite automatizar la generación de perfiles de Baseline.

El asistente también realiza cambios en el módulo de la app de destino que seleccionaste. En particular, se aplica el complemento androidx.baselineprofile, se agrega la dependencia androidx.profileinstaller y, por último, se agrega la dependencia baselineProfile al módulo build.gradle(.kts) recién creado:

plugins {
  id("androidx.baselineprofile")
}

dependencies {
  // ...
  implementation("androidx.profileinstaller:profileinstaller:1.3.0")
  "baselineProfile"(project(mapOf("path" to ":baselineprofile")))
}

Agregar la dependencia androidx.profileinstaller permite hacer lo siguiente:

  • Verificar localmente las mejoras del rendimiento de los perfiles de Baseline generados.
  • Usar perfiles de Baseline en Android 7 (nivel de API 24) y Android 8 (nivel de API 26), que no son compatibles con los perfiles de Cloud.
  • Usar los perfiles de Baseline en dispositivos que no cuenten con los Servicios de Google Play.

La dependencia baselineProfile(project(":baselineprofile")) permite que Gradle sepa desde qué módulo tiene que tomar los perfiles de Baseline generados.

Ahora que el proyecto está configurado, escribe una clase de generador de perfiles de Baseline.

5. Escribe un generador de perfiles de Baseline

Por lo general, se generan perfiles de Baseline para los recorridos del usuario típicos de tu app.

El asistente de módulos crea una clase de prueba BaselineProfileGenerator básica que puede generar los perfiles para el inicio de tu app y se ve de la siguiente manera:

@RunWith(AndroidJUnit4::class)
@LargeTest
class BaselineProfileGenerator {

    @get:Rule
    val rule = BaselineProfileRule()

    @Test
    fun generate() {
        rule.collect("com.example.baselineprofiles_codelab") {
            // This block defines the app's critical user journey. This is where you
            // optimize for app startup. You can also navigate and scroll
            // through your most important UI.

            // Start default activity for your app.
            pressHome()
            startActivityAndWait()

            // TODO Write more interactions to optimize advanced journeys of your app.
            // For example:
            // 1. Wait until the content is asynchronously loaded.
            // 2. Scroll the feed content.
            // 3. Navigate to detail screen.

            // Check UiAutomator documentation for more information about how to interact with the app.
            // https://d.android.com/training/testing/other-components/ui-automator
        }
    }
}

Esta clase usa una regla de prueba BaselineProfileRule y contiene un método de prueba de generación de perfil. El punto de entrada a los efectos de generar el perfil es la función collect(). Solo requiere dos parámetros:

  • packageName: Es el paquete de tu app.
  • profileBlock: Es el último parámetro de la lambda.

En la lambda de profileBlock, puedes especificar las interacciones que abarcan el recorrido típico del usuario de tu app. La biblioteca ejecuta profileBlock varias veces, recopila las clases y funciones a las que se llamó y genera el perfil de Baseline en el dispositivo con el código que se optimizará.

De forma predeterminada, la clase de generación creada contiene interacciones para iniciar tu Activity predeterminada y espera a que se renderice el primer fotograma de tu app mediante el método startActivityAndWait().

Extiende el generador con recorridos personalizados

Puedes ver que la clase generada también incluye algunos elementos TODO para escribir más interacciones y optimizar los recorridos avanzados de tu app. Esto es recomendable para que puedas optimizar el rendimiento más allá del inicio de la app.

Para identificar estos recorridos, puedes hacer lo siguiente en nuestra app de ejemplo:

  1. Inicia la aplicación. Esta acción ya está parcialmente cubierta por la clase generada.
  2. Espera hasta que el contenido se cargue de forma asíncrona.
  3. Desplázate por la lista de bocadillos.
  4. Ve al detalle del bocadillo.

Modifica el generador para que contenga las funciones detalladas que abarcan los recorridos típicos en el siguiente fragmento:

// ...
rule.collect("com.example.baselineprofiles_codelab") {
    // This block defines the app's critical user journey. This is where you
    // optimize for app startup. You can also navigate and scroll
    // through your most important UI.

    // Start default activity for your app.
    pressHome()
    startActivityAndWait()

    // TODO Write more interactions to optimize advanced journeys of your app.
    // For example:
    // 1. Wait until the content is asynchronously loaded.
    waitForAsyncContent()
    // 2. Scroll the feed content.
    scrollSnackListJourney()
    // 3. Navigate to detail screen.
    goToSnackDetailJourney()

    // Check UiAutomator documentation for more information about how to interact with the app.
    // https://d.android.com/training/testing/other-components/ui-automator
}
// ...

Ahora, escribe interacciones para cada recorrido mencionado. Puedes escribirlas como la función de extensión de MacrobenchmarkScope para tener acceso a los parámetros y las funciones que proporciona. Escribirlas de esta forma te permite volver a utilizarlas con las comparativas para verificar las mejoras del rendimiento.

Espera por el contenido asíncrono

Muchas apps tienen algún tipo de carga asíncrona durante el inicio, al que también se conoce como estado mostrado por completo, que le indica al sistema cuando el contenido se termine de cargar y renderizar y esté listo para que el usuario interactúe con él. Espera por el estado en el generador (waitForAsyncContent) con estas interacciones:

  1. Busca la lista de bocadillos.
  2. Espera hasta que algunos de los elementos de la lista sean visibles en pantalla.
fun MacrobenchmarkScope.waitForAsyncContent() {
   device.wait(Until.hasObject(By.res("snack_list")), 5_000)
   val contentList = device.findObject(By.res("snack_list"))
   // Wait until a snack collection item within the list is rendered.
   contentList.wait(Until.hasObject(By.res("snack_collection")), 5_000)
}

Recorrido por la lista de desplazamiento

Para obtener el recorrido por la lista de desplazamiento de bocadillos (scrollSnackListJourney), puedes seguir estas interacciones:

  1. Busca el elemento de la IU de la lista de bocadillos.
  2. Establece los márgenes gestuales para evitar que se active la navegación del sistema.
  3. Desplázate por la lista y espera hasta que la IU se detenga.
fun MacrobenchmarkScope.scrollSnackListJourney() {
   val snackList = device.findObject(By.res("snack_list"))
   // Set gesture margin to avoid triggering gesture navigation.
   snackList.setGestureMargin(device.displayWidth / 5)
   snackList.fling(Direction.DOWN)
   device.waitForIdle()
}

Cómo ir al recorrido detallado

El último recorrido (goToSnackDetailJourney) implementa estas interacciones:

  1. Buscar la lista de bocadillos y todos aquellos con los que puedas trabajar.
  2. Seleccionar un elemento de la lista.
  3. Hacer clic en el elemento y esperar hasta que se cargue la pantalla de detalles. Puedes aprovechar el hecho de que la lista de bocadillos ya no aparecerá en la pantalla.
fun MacrobenchmarkScope.goToSnackDetailJourney() {
    val snackList = device.findObject(By.res("snack_list"))
    val snacks = snackList.findObjects(By.res("snack_item"))
    // Select snack from the list based on running iteration.
    val index = (iteration ?: 0) % snacks.size
    snacks[index].click()
    // Wait until the screen is gone = the detail is shown.
    device.wait(Until.gone(By.res("snack_list")), 5_000)
}

Una vez que definas todas las interacciones necesarias para ejecutar el generador de perfiles de Baseline, deberás definir el dispositivo en el que lo hará.

6. Prepara un dispositivo para que el generador se ejecute en él

Para generar los perfiles de Baseline, recomendamos que uses un emulador, como un dispositivo administrado por Gradle, o un dispositivo que ejecute Android 13 (nivel de API 33) o una versión más reciente.

Para automatizar la generación de perfiles de Baseline y que el proceso sea reproducible, puedes usar un dispositivo administrado por Gradle. Este tipo de dispositivos te permiten ejecutar pruebas en un emulador de Android sin necesidad de iniciarlo y desmontarlo de forma manual. Para obtener más información sobre los dispositivos administrados por Gradle, consulta Ajusta tus pruebas con dispositivos administrados por Gradle.

Para definir un dispositivo administrado por Gradle, agrega si definición al módulo :baselineprofile del archivo build.gradle.kts como se muestra en el siguiente fragmento:

android {
  // ...

  testOptions.managedDevices.devices {
    create<ManagedVirtualDevice>("pixel6Api31") {
        device = "Pixel 6"
        apiLevel = 31
        systemImageSource = "aosp"
    }
  }
}

En este caso, usamos Android 11 (nivel de API 31) y la imagen del sistema aosp tiene acceso con permisos de administrador.

A continuación, configura el complemento de Gradle para perfiles de Baseline para usar el dispositivo administrado por Gradle definido. Para ello, agrega el nombre del dispositivo a la propiedad managedDevices e inhabilita useConnectedDevices como se muestra en el siguiente fragmento:

android {
  // ...
}

baselineProfile {
   managedDevices += "pixel6Api31"
   useConnectedDevices = false
}

dependencies {
  // ...
}

A continuación, genera el perfil de Baseline.

7. Genera el perfil de Baseline

Una vez que el dispositivo esté listo, puedes crear el perfil de Baseline. El complemento de Gradle para perfiles de Baseline crea tareas de Gradle para automatizar todo el proceso de ejecución de la clase de prueba del generador y de aplicación de los perfiles de Baseline generados en tu app.

El asistente de módulos nuevos creó una configuración de ejecución para realizar rápidamente la tarea de Gradle con todos los parámetros necesarios, sin necesidad de cambiar entre la terminal y Android Studio.

Para ejecutarla, busca la configuración de ejecución Generate Baseline Profile y haz clic en el botón Run 599be5a3531f863b.png.

6911ecf1307a213f.png

La tarea inicia la imagen del emulador que se definió anteriormente. Ejecuta las interacciones desde la clase de prueba BaselineProfileGenerator varias veces. Luego, desmantela el emulador y envía los resultados a Android Studio.

Una vez que el generador finaliza su tarea, el complemento de Gradle coloca automáticamente el baseline-prof.txt generado en la app de destino (módulo :app) en la carpeta src/release/generated/baselineProfile/.

fa0f52de5d2ce5e8.png

Ejecuta el generador desde la línea de comandos (opcional)

De forma alternativa, puedes ejecutar el generador desde la línea de comandos. Puedes aprovechar las tareas que creó el dispositivo administrado por Gradle: :app:generateBaselineProfile. Este comando ejecuta todas las pruebas del proyecto que se definieron en la dependencia baselineProfile(project(:baselineProfile)). Debido a que el módulo también contiene comparativas para una posterior verificación de mejoras de rendimiento, las pruebas fallan con una advertencia que desaconseja la ejecución de comparativas en un emulador.

android
   .testInstrumentationRunnerArguments
   .androidx.benchmark.enabledRules=BaselineProfile

Para ello, puedes filtrar todos los generadores de perfiles de Baseline con los siguientes argumentos de ejecutor de instrumentación y se omitirán todas las comparativas:

El comando completo se verá de la siguiente manera:

./gradlew :app:generateBaselineProfile -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile

Cómo distribuir tu app con perfiles de Baseline

Una vez que el perfil de Baseline se genera y se copia en el código fuente de la app, compila la versión de producción como lo harías normalmente. No necesitas realizar acciones adicionales para distribuir los perfiles de Baseline a tus usuarios, ya que el complemento de Android para Gradle los elige durante la compilación y los incluye en tu AAB o APK. A continuación, carga la compilación en Google Play.

Cuando los usuarios instalen la app o la actualicen desde la versión anterior, también se instala el perfil de Baseline, lo que tiene como resultado un mejor rendimiento desde la primera vez que se ejecuta la app.

En el próximo paso se muestra cómo verificar cuánto mejoró el rendimiento de la app con los perfiles de Baseline.

8. Personaliza la generación de perfiles de Baseline (opcional)

El complemento de Gradle para perfiles de Baseline incluye opciones para personalizar la forma en que se generan los perfiles para satisfacer tus necesidades específicas. Puedes cambiar su comportamiento con el bloque de configuración baselineProfile { } que se encuentra en las secuencias de comandos de compilación.

El bloque de configuración que se encuentra en el módulo :baselineprofile afecta la ejecución de los generadores con la posibilidad de agregar managedDevices y decidir si usar useConnectedDevices o dispositivos administrados por Gradle.

El bloque de configuración del módulo de destino :app decide dónde se guardan los perfiles o cómo se generan. Puedes modificar los siguientes parámetros:

  • automaticGenerationDuringBuild: Si activas este parámetro, puedes generar el perfil de Baseline cuando compilas la compilación de lanzamiento de producción. Esto es útil si compilas en CI antes de enviar la app.
  • saveInSrc: Especifica si los perfiles de Baseline que se generaron se almacenan en la carpeta src/. Opcionalmente, puedes acceder al archivo desde la carpeta de compilación :baselineprofile.
  • baselineProfileOutputDir: Define dónde se almacenarán los perfiles de Baseline que se generaron.
  • mergeIntoMain: De forma predeterminada, los perfiles de Baseline se generan según la variante de compilación (variante de producto y tipo de compilación). Si deseas fusionar todos los perfiles en src/main, puedes habilitar esta marca para hacerlo.
  • filter: Permite filtrar las clases o métodos que se incluirán o excluirán de los perfiles de Baseline. Esto puede ser útil para los desarrolladores de bibliotecas que solo quieren el código de la biblioteca incluida.

9. Verifica las mejoras del rendimiento del inicio

Una vez que generes un perfil de Baseline y lo agregues a la app, verifica que tenga el efecto deseado en el rendimiento de la app.

El asistente de módulos nuevos crea una clase de comparativas llamada StartupBenchmarks. Contiene una comparativa para medir el tiempo de inicio de la app y lo compara con el tiempo de inicio usando perfiles de Baseline.

La clase se ve así:

@RunWith(AndroidJUnit4::class)
@LargeTest
class StartupBenchmarks {

    @get:Rule
    val rule = MacrobenchmarkRule()

    @Test
    fun startupCompilationNone() =
        benchmark(CompilationMode.None())

    @Test
    fun startupCompilationBaselineProfiles() =
        benchmark(CompilationMode.Partial(BaselineProfileMode.Require))

    private fun benchmark(compilationMode: CompilationMode) {
        rule.measureRepeated(
            packageName = "com.example.baselineprofiles_codelab",
            metrics = listOf(StartupTimingMetric()),
            compilationMode = compilationMode,
            startupMode = StartupMode.COLD,
            iterations = 10,
            setupBlock = {
                pressHome()
            },
            measureBlock = {
                startActivityAndWait()

                // TODO Add interactions to wait for when your app is fully drawn.
                // The app is fully drawn when Activity.reportFullyDrawn is called.
                // For Jetpack Compose, you can use ReportDrawn, ReportDrawnWhen and ReportDrawnAfter
                // from the AndroidX Activity library.

                // Check the UiAutomator documentation for more information on how to
                // interact with the app.
                // https://d.android.com/training/testing/other-components/ui-automator
            }
        )
    }
}

Utiliza MacrobenchmarkRule, que puede ejecutar comparativas para tu app y reunir métricas de rendimiento. El punto de entrada para la escritura de una comparativa es la función measureRepeated de la regla.

Varios parámetros son necesarios:

  • packageName:: Indica qué app se medirá.
  • metrics: Se trata del tipo de información que deseas medir durante las comparativas.
  • iterations: Indica cuántas veces se repetirá la comparativa.
  • startupMode: Indica cómo deseas que se inicie tu app al inicio de las comparativas.
  • setupBlock: Indica qué interacciones con la app deben suceder antes de la medición.
  • measureBlock: Se trata de las interacciones con tu app que deseas medir con las comparativas.

La clase de prueba también contiene dos pruebas: startupCompilationeNone() y startupCompilationBaselineProfiles(), que llaman a la función benchmark() con compilationMode diferente.

CompilationMode

El parámetro CompilationMode define cómo se compila previamente la aplicación en código máquina. Tiene las siguientes opciones:

  • DEFAULT: Hace una compilación previa parcial de la app mediante perfiles de Baseline, si están disponibles. Esto se usa si no se aplica ningún parámetro compilationMode.
  • None(): Restablece el estado de compilación de la app y no realiza una compilación previa. La compilación justo a tiempo (JIT) continúa habilitada durante la ejecución de la app.
  • Partial(): Hace una compilación previa de la app con perfiles de Baseline, ejecuciones de preparación o con ambos.
  • Full(): Hace una compilación previa de todo el código de la aplicación. Esta es la única opción en Android 6 (nivel de API 23) y versiones anteriores.

Si quieres comenzar a optimizar el rendimiento de tu aplicación, puedes elegir el modo de compilación DEFAULT, que es similar a cuando se instala la app desde Google Play. Si deseas comparar los beneficios de rendimiento que ofrecen los perfiles de Baseline, puedes hacerlo comparando los resultados de los modos de compilación None y Partial.

Modifica la comparativa para que espere contenido

Las comparativas se escriben de forma similar a los generadores de perfiles de Baseline escribiendo interacciones con tu app. De forma predeterminada, las comparativas creadas solo esperan a que se renderice el primer fotograma (parecido a cómo lo hizo BaselineProfileGenerator), por lo que recomendamos que la mejores para que espere por el contenido asíncrono.

Para hacerlo, puedes reutilizar las funciones de extensión que escribiste para el generador. Debido a que esta comparativa solo captura los tiempos de inicio mediante StartupTimingMetric(), te recomendamos que solo incluyas la espera por el contenido asíncrono aquí y, luego, escribas una por separado para los demás recorridos del usuario definidos en el generador.

// ...
measureBlock = {
   startActivityAndWait()

   // The app is fully drawn when Activity.reportFullyDrawn is called.
   // For Jetpack Compose, you can use ReportDrawn, ReportDrawnWhen and ReportDrawnAfter
   // from the AndroidX Activity library.
   waitForAsyncContent() // <------- Added to wait for async content.

   // Check the UiAutomator documentation for more information on how to
   // interact with the app.
   // https://d.android.com/training/testing/other-components/ui-automator
}

Ejecuta las comparativas

Puedes ejecutar las comparativas igual que ejecutas las pruebas de instrumentación. Puedes ejecutar la función de prueba o toda la clase con el ícono de margen junto a ella.

587b04d1a76d1e9d.png

Asegúrate de tener un dispositivo físico seleccionado, ya que la ejecución de comparativas en un emulador de Android falla durante el tiempo de ejecución con una advertencia que indica que puede arrojar resultados incorrectos. Si bien, técnicamente, puedes ejecutar la comparativa en un emulador, estarás midiendo el rendimiento de la máquina anfitrión. Si la máquina se encuentra demasiado exigida, las comparativas parecerán más lentas y viceversa.

94e0da86b6f399d5.png

Una vez que ejecutes las comparativas, se volverá a compilar tu app y a ejecutar las comparativas, que inician tu app, la detienen e, incluso, la reinstalan varias veces según las iterations que definas.

Una vez que se completen, podrás ver los tiempos en el resultado de Android Studio, como se muestra en la siguiente captura de pantalla:

282f90d5f6ff5196.png

En la captura de pantalla, puedes ver que la hora de inicio de la app es diferente para cada CompilationMode. Los valores de la mediana se muestran en la siguiente tabla:

timeToInitialDisplay [ms]

timeToFullDisplay [ms]

Ninguno

202.2

818.8

Perfiles de Baseline

193.7

637.9

Mejora

4%

28%

La diferencia entre los modos de compilación de timeToFullDisplay es de 180 ms, que es una mejora de aproximadamente el 28% gracias a la implementación de un perfil de Baseline. El rendimiento de CompilationNone disminuye debido a que el dispositivo debe hacer la mayor parte de la compilación JIT durante el inicio de la app. El rendimiento de CompilationBaselineProfiles mejora porque la compilación parcial anticipada con perfiles de Baseline compila el código que el usuario utilizará con mayor probabilidad y no compila previamente el código que no es crítico de modo que no deba cargarse de inmediato.

10. Verifica la mejora del rendimiento del desplazamiento (opcional)

Al igual que en los pasos anteriores, puedes medir y verificar el rendimiento del desplazamiento. Primero, crea una clase de prueba ScrollBenchmarks con la regla de comparativa y dos métodos de prueba que usen diferentes modos de compilación:

@LargeTest
@RunWith(AndroidJUnit4::class)
class ScrollBenchmarks {

   @get:Rule
   val rule = MacrobenchmarkRule()

   @Test
   fun scrollCompilationNone() = scroll(CompilationMode.None())

   @Test
   fun scrollCompilationBaselineProfiles() = scroll(CompilationMode.Partial())

   private fun scroll(compilationMode: CompilationMode) {
       // TODO implement
   }
}

Desde el método scroll, usa la función measureRepeated con el parámetro requerido. En el parámetro metrics, usa FrameTimingMetric, que mide el tiempo que se demora en producir los fotogramas de la IU:

private fun scroll(compilationMode: CompilationMode) {
   rule.measureRepeated(
       packageName = "com.example.baselineprofiles_codelab",
       metrics = listOf(FrameTimingMetric()),
       compilationMode = compilationMode,
       startupMode = StartupMode.WARM,
       iterations = 10,
       setupBlock = {
           // TODO implement
       },
       measureBlock = {
           // TODO implement
       }
   )
}

Esta vez, tendrás que dividir más las interacciones entre setupBlock y measureBlock para medir la duración de los fotogramas solo la primera vez que se muestra el diseño al usuario, y que este se desplaza por el contenido. Por lo tanto, pon las funciones que inician la pantalla predeterminada en setupBlock y las funciones de extensión waitForAsyncContent() y scrollSnackListJourney() que se crearon en measureBlock:

private fun scroll(compilationMode: CompilationMode) {
   rule.measureRepeated(
       packageName = "com.example.baselineprofiles_codelab",
       metrics = listOf(FrameTimingMetric()),
       compilationMode = compilationMode,
       startupMode = StartupMode.WARM,
       iterations = 10,
       setupBlock = {
           pressHome()
           startActivityAndWait()
       },
       measureBlock = {
           waitForAsyncContent()
           scrollSnackListJourney()
       }
   )
}

Una vez que la comparativa esté lista, podrás ejecutarla como antes para obtener resultados, como se muestra en la siguiente captura de pantalla:

84aa99247226fc3a.png

FrameTimingMetric muestra la duración de los fotogramas en milisegundos (frameDurationCpuMs) en los percentiles 50, 90, 95 y 99. En Android 12 (nivel de API 31) y versiones posteriores, también muestra cuánto tiempo los fotogramas superan el límite (frameOverrunMs). El valor puede ser negativo, lo que significa que hubo un resto de tiempo disponible para producir el fotograma.

Una vez que tengas los resultados, podrás ver que CompilationBaselineProfiles tiene una duración de fotograma aproximadamente 2 ms más corta, que es posible que los usuarios no noten. Sin embargo, en los otros percentiles, los resultados son más evidentes. Para P99, la diferencia es de 43.5 ms, que es más de 3 fotogramas omitidos en un dispositivo que funciona a 90 FPS. Por ejemplo, en el caso del Pixel 6, la renderización de un fotograma es de 1,000 ms / 90 FPS = ~11 ms como máximo.

11. Felicitaciones

¡Felicitaciones! Completaste correctamente este codelab y mejoraste el rendimiento de tu app con los perfiles de Baseline.

Recursos adicionales

Consulta los siguientes recursos adicionales:

Documentos de referencia