Cómo escribir una macrocomparativa

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

Usa la biblioteca de Macrobenchmark para probar los casos de uso más grandes de tu aplicación, incluido su inicio y las manipulaciones de IU complejas, como desplazarse por una RecyclerView o ejecutar animaciones. Si quieres probar partes más pequeñas de tu código, consulta la biblioteca de Microcomparativas.

La biblioteca genera resultados de comparativas tanto en la consola de Android Studio como en un archivo JSON con más detalles. También proporciona archivos de registro que puedes cargar y analizar en Android Studio.

Usa la Biblioteca de macrocomparativas en un entorno de integración continua (CI) tal como se describe en Cómo ejecutar comparativas en la integración continua.

Los perfiles de Baseline se pueden generar con macrocomparativas. Sigue la guía que se encuentra a continuación para configurar la Biblioteca de macrocomparativas y, luego, crea un perfil de modelo de referencia.

Configuración del proyecto

Te recomendamos que uses Macrobenchmark con la versión más reciente de Android Studio, ya que hay funciones nuevas en esa versión del IDE que se integran con Macrobenchmark.

Configura el módulo de Macrobenchmark

Las macrocomparativas requieren un módulo com.android.test independiente del código de tu app en el que se ejecuten las pruebas que miden la app.

En Android Studio, hay una plantilla disponible para simplificar la configuración del módulo de Macrobenchmark. Esta plantilla crea automáticamente un módulo en el proyecto para medir la app que compila un módulo de app, incluida una comparativa de inicio de muestra.

Si deseas usar la plantilla del módulo a fin de crear un módulo nuevo, haz lo siguiente:

  1. Haz clic con el botón derecho en tu proyecto o módulo desde el panel Project en Android Studio y, luego, haz clic en New > Module.

  2. Selecciona Benchmark en el panel Templates.

  3. Puedes personalizar la aplicación de destino (la app de la que obtendrás comparativas), así como el nombre del paquete y del módulo para el módulo nuevo de macrocomparativas.

  4. Haz clic en Finish.

Plantilla del módulo de comparativas

Configura la aplicación

Para obtener comparativas de una app (denominada el objetivo de la macrocomparativa), esta debe ser profileable, lo que permite leer información de seguimiento detallada sin afectar el rendimiento. El asistente de módulos agrega la etiqueta <profileable> automáticamente al archivo AndroidManifest.xml de la app.

Configura la app de la que obtendrás comparativas de la forma más parecida posible a la versión de actualización (o producción). Además, configúrala como no depurable y con la reducción activada en lo posible, lo que mejorará el rendimiento. Para ello, en general, debes crear una copia de la variante de la versión, que tendrá el mismo rendimiento, pero se firma de manera local con claves de depuración. Como alternativa, puedes usar initWith para indicar a Gradle que lo haga por ti:

Groovy

buildTypes {
    release {
        minifyEnabled true
        shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }

    benchmark {
        initWith buildTypes.release
        signingConfig signingConfigs.debug
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'benchmark-rules.pro'
    }
}

Kotlin

buildTypes {
    getByName("release") {
        isMinifyEnabled = true
        isShrinkResources = true
        proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))
    }

    create("benchmark") {
        initWith(getByName("release"))
        signingConfig = signingConfigs.getByName("debug")
    }
}

Realiza una sincronización de Gradle, abre el panel Build Variants en el lado izquierdo y selecciona la variante de comparativas de la app y del módulo de macrocomparativas. De esta manera, te aseguras de que con la ejecución de las comparativas se compile y se pruebe la variante correcta de tu app.

Selecciona una variante de comparativas

(Opcional) Configura una aplicación con varios módulos

Si tu app tiene más de un módulo de Gradle, debes asegurarte de que las secuencias de comandos de compilación sepan la variante de compilación que deben compilar. De lo contrario, el buildType benchmark que se agregó recientemente hace que la compilación falle y muestra el siguiente mensaje de error:

> Could not resolve project :shared.
     Required by:
         project :app
      > No matching variant of project :shared was found.
      ...

Para solucionar el problema, agrega la propiedad matchingFallbacks al buildType benchmark de los módulos :macrobenchmark y :app. El resto de los módulos de Gradle puede tener la misma configuración que antes.

Groovy

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
}

Kotlin

create("benchmark") {
    initWith(getByName("release"))
    signingConfig = signingConfigs.getByName("debug")

    matchingFallbacks += listOf('release')
}

Cuando selecciones las variantes de compilación de tu proyecto, elige benchmark para los módulos :app y :macrobenchmark, y release para cualquier otro módulo que tengas en tu app, como se muestra en la siguiente imagen:

Variantes de comparativas para un proyecto de varios módulos con versiones de buildTypes y comparativas

Si quieres obtener más información, consulta el artículo para administrar dependencias con reconocimiento de variantes.

(Opcional) Configura las variantes de producto

Si configuraste más de una variante de producto en la app, debes configurar el módulo :macrobenchmark para que sepa qué tipo de variante compilar y comparar. Sin esta configuración, es posible que recibas un error de compilación similar al de varios módulos de Gradle:

Could not determine the dependencies of task ':macrobenchmark:connectedBenchmarkAndroidTest'.
> Could not determine the dependencies of null.
   > Could not resolve all task dependencies for configuration ':macrobenchmark:benchmarkTestedApks'.
      > Could not resolve project :app.
        Required by:
            project :macrobenchmark
         > The consumer was configured to find a runtime of a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'benchmark', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.3.0'. However we cannot choose between the following variants of project :app:
             - demoBenchmarkRuntimeElements
             - productionBenchmarkRuntimeElements
           All of them match the consumer attributes:
           ...

Para esta guía, usaremos las dos variantes de producto de nuestro módulo :app (demo y production), como puedes ver en el siguiente fragmento:

Groovy

flavorDimensions 'environment'
productFlavors {
    demo {
        dimension 'environment'
        // ...
    }

    production {
        dimension 'environment'
        // ...
    }
}

Kotlin

flavorDimensions += "environment"
productFlavors {
    create("demo") {
        dimension = "environment"
        // ...
    }
    create("production") {
        dimension = "environment"
        // ...
    }
}

Hay dos formas de configurar las comparativas con más de una variante de producto:

Usa missingDimensionStrategy

La especificación de missingDimensionStrategy en el defaultConfig del módulo :macrobenchmark le indica al sistema de compilación que recurra a la dimensión de variantes. Si las dimensiones no se encuentran en el módulo, debes especificar cuáles buscar. En el siguiente ejemplo, se usa la variante production como dimensión predeterminada:

Groovy

defaultConfig {
    missingDimensionStrategy "environment", "production"
}

Kotlin

defaultConfig {
    missingDimensionStrategy("environment", "production")
}

De esta manera, el módulo :macrobenchmark solo puede compilar y comparar las variantes de productos especificadas, lo que es útil si sabes que solo una variante de producto tiene la configuración adecuada para obtener comparativas.

Define las variantes de productos en el módulo :macrobenchmark

Si deseas compilar y comparar otras variantes de producto, debes definirlas en el módulo :macrobenchmark. Especifícala del mismo modo que en el módulo :app, pero solo asigna productFlavors a dimension; no se requieren otras opciones de configuración:

Groovy

flavorDimensions 'environment'
productFlavors {
    demo {
        dimension 'environment'
    }

    production {
        dimension 'environment'
    }
}

Kotlin

flavorDimensions += "environment"
productFlavors {
    create("demo") {
        dimension = "environment"
    }
    create("production") {
        dimension = "environment"
    }
}

Una vez definido y sincronizado el proyecto, elige la variante de compilación que desees desde el panel Build Variants:

Variantes de comparativas para el proyecto con variantes de producto que muestran el módulo productionBenchmark y las versiones seleccionadas

Para obtener más información, consulta Cómo corregir errores de compilación relacionados con la coincidencia de variantes.

Cómo crear una clase de macrocomparativas

Las pruebas de comparativas se proporcionan mediante la API de la regla MacrobenchmarkRule de JUnit4 en la biblioteca de Macrobenchmark. Dicha biblioteca contiene un método measureRepeated que te permite especificar varias condiciones para ejecutar y comparar la aplicación de destino.

Como mínimo, debes especificar el packageName de la aplicación de destino, las metrics que deseas medir y la cantidad de iterations que debe ejecutar la comparativa.

Kotlin

@LargeTest
@RunWith(AndroidJUnit4::class)
class SampleStartupBenchmark {
    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()

    @Test
    fun startup() = benchmarkRule.measureRepeated(
        packageName = TARGET_PACKAGE,
        metrics = listOf(StartupTimingMetric()),
        iterations = 5,
        setupBlock = {
            // Press home button before each run to ensure the starting activity isn't visible.
            pressHome()
        }
    ) {
        // starts default launch activity
        startActivityAndWait()
    }
}

Java

@LargeTest
@RunWith(AndroidJUnit4.class)
public class SampleStartupBenchmark {
    @Rule
    public MacrobenchmarkRule benchmarkRule = new MacrobenchmarkRule();

    @Test
    public void startup() {
        benchmarkRule.measureRepeated(
            /* packageName */ TARGET_PACKAGE,
            /* metrics */ Arrays.asList(new StartupTimingMetric()),
            /* iterations */ 5,
            /* measureBlock */ scope -> {
                // starts default launch activity
                scope.startActivityAndWait();
                return Unit.INSTANCE;
            }
        );
    }
}

Si deseas conocer todas las opciones para personalizar las comparativas, consulta la sección Cómo personalizar las comparativas.

Cómo ejecutar las comparativas

Ejecuta la prueba desde Android Studio a fin de medir el rendimiento de la app en tu dispositivo. Puedes ejecutar las comparativas como lo harías con cualquier otra @Test con la acción del margen junto a tu clase o método de prueba, como se muestra en la siguiente imagen.

Ejecuta macrocomparativas con la acción del margen junto a la clase de prueba

Puedes ejecutar todas las comparativas en un módulo de Gradle desde la línea de comandos mediante la ejecución del comando connectedCheck:

./gradlew :macrobenchmark:connectedCheck

También puedes ejecutar una sola prueba:

./gradlew :macrobenchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.macrobenchmark.startup.SampleStartupBenchmark#startup

Consulta la sección Comparativas en CI a fin de obtener información para ejecutar y supervisar comparativas en integración continua.

Resultados de comparativas

Después de generar una comparativa con éxito, las métricas se muestran directamente en Android Studio y como resultados del uso de CI en un archivo JSON. Cada iteración medida captura un registro del sistema diferente. Para abrir estos registros de resultado, haz clic en uno de los vínculos que se incluyen en el panel Test Results, como se muestra en la siguiente imagen.

Resultados de macrocomparativas del inicio

Cuando se carga el registro, Android Studio te solicita que selecciones el proceso a analizar. La selección se prepropaga con el proceso de la app de destino, como se muestra a continuación:

Selección del proceso de registro de Studio

Una vez cargado el archivo de registro, Studio muestra los resultados en la herramienta del Generador de perfiles de CPU:

Registro de Studio

Los informes de JSON y cualquier seguimiento de perfiles también se copian automáticamente del dispositivo al host. Están escritos en la máquina anfitrión en:

project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/

Accede a los archivos de registro de forma manual

Si deseas utilizar la herramienta Perfetto para analizar un archivo de registro, debes seguir algunos pasos adicionales. Perfetto te permite inspeccionar todos los procesos que se realizan en el dispositivo durante el registro. En cambio, el Generador de perfiles de CPU de Android Studio limita la inspección a un único proceso.

Si invocas las pruebas desde Android Studio o con la línea de comandos de Gradle, los archivos de registro se copian automáticamente del dispositivo al host. Estos están escritos en la máquina anfitrión en la siguiente string:

project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/TrivialStartupBenchmark_startup[mode=COLD]_iter002.perfetto-trace

Cuando tengas el archivo de registro en tu sistema host, puedes abrirlo en Android Studio con las opciones File > Open del menú. Esta opción muestra la vista de la herramienta del generador de perfiles que se proporcionó en la sección anterior.

Errores de configuración

Si la app está mal configurada (es depurable o no permite que se generen perfiles), Macrobenchmark mostrará un error, en lugar de informar una medición incorrecta o incompleta. Puedes suprimir esos errores con el argumento androidx.benchmark.suppressErrors.

Además, se arrojan errores cuando se intenta medir un emulador o si el dispositivo tiene poca batería, dado que se podría comprometer la disponibilidad principal y la velocidad del reloj.

Cómo personalizar las comparativas

La función measureRepeated acepta varios parámetros que influyen en qué métricas recopila la biblioteca, cómo se inicia y compila tu aplicación, y cuántas iteraciones ejecutará la comparativa.

Cómo capturar las métricas

Las métricas son el tipo principal de información que se extrae de tus comparativas. Las opciones disponibles son StartupTimingMetric, FrameTimingMetric y TraceSectionMetric. Si deseas obtener más información sobre ellas, consulta la página Cómo capturar las métricas.

Cómo mejorar los datos de registro con eventos personalizados

Te puede resultar útil instrumentar la aplicación con eventos de registro personalizados, que se muestran con el resto del informe de registro y pueden ayudar a identificar problemas específicos de tu app. Si quieres obtener más información sobre la creación de eventos de registro personalizados, consulta la guía Cómo definir eventos personalizados.

CompilationMode

Las macrocomparativas pueden especificar un CompilationMode, que define cuánto de la app se debe compilar previamente desde el código de bytes DEX (el formato de código de bytes dentro de un APK) al código máquina (similar a C++ ya compilado).

De forma predeterminada, las macrocomparativas se ejecutan con CompilationMode.DEFAULT, que instala un perfil de Baseline (si está disponible) en Android 7 (nivel de API 24) y versiones posteriores. Si usas Android 6 (nivel de API 23) o versiones anteriores, el modo de compilación compila por completo el APK como el comportamiento predeterminado del sistema.

Puedes instalar un perfil de Baseline si la aplicación de destino contiene este tipo de perfil y la biblioteca de ProfileInstaller.

En Android 7 y versiones posteriores, puedes personalizar el CompilationMode para que afecte la cantidad de compilación previa en el dispositivo, a fin de imitar diferentes niveles de compilación anticipada (AOT) o almacenamiento en caché de JIT. Consulta CompilationMode.Full, CompilationMode.Partial y CompilationMode.None.

Esta funcionalidad se basa en comandos de compilación de ART. Para garantizar que no haya interferencias entre las comparativas, cada una borrará los datos de perfil antes de comenzar.

StartupMode

A fin de iniciar una actividad, puedes pasar un modo de inicio predefinido (que puede ser COLD, WARM o HOT). Este parámetro cambia la forma en que se inicia la actividad así como el estado del proceso al comienzo de la prueba.

Si quieres obtener más información sobre los tipos de inicio, consulta la documentación de inicio de Android Vitals.

Ejemplos

En GitHub, encontrarás un proyecto de ejemplo en el repositorio android/performance-samples.

Cómo enviar comentarios

Si deseas informar errores o enviar solicitudes de funciones de Jetpack Macrobenchmark, consulta la Herramienta de seguimiento de errores pública.