Cómo escribir una macrocomparativa

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.

Además, puedes usar la biblioteca de Macrobenchmark en un entorno de integración continua (CI), como se describe en Cómo ejecutar comparativas en integración continua.

Configuración del proyecto

Te recomendamos que uses Macrobenchmark con la versión más reciente de Android Studio (Bumblebee 2021.1.1 o una versión posterior), ya que en ella se incluyen nuevas funciones del IDE que se integran con Macrobenchmark.

Cómo configurar el módulo de macrocomparativas

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.

Bumblebee (o una versión más reciente)

En Android Studio Bumblebee 2021.1.1, hay una plantilla disponible para simplificar la configuración del módulo de macrocomparativas. La plantilla del módulo de comparativas 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

Arctic Fox

En Arctic Fox, crearás un módulo de biblioteca y lo convertirás en un módulo de prueba.

  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 Android Library en el panel Templates.
  3. Como nombre de módulo, escribe macrobenchmark.
  4. Configura Minimum SDK en API 23: Android M.
  5. Haz clic en Finish.

Configuración de un nuevo módulo de biblioteca

Cómo modificar el archivo de Gradle

Personaliza el build.gradle del módulo de Macrobenchmark como se indica a continuación:

  1. Cambia el complemento de com.android.library a com.android.test.
    apply plugin 'com.android.test'
  2. Agrega las propiedades adicionales y obligatorias del módulo de prueba en el bloque android {}:

    Groovy

    android {
        // ...
        // Note that your module name may have different name
        targetProjectPath = ":app"
        // Enable the benchmark to run separately from the app process
        experimentalProperties["android.experimental.self-instrumenting"] = true
    
        buildTypes {
            // declare a build type to match the target app's build type
            benchmark {
                debuggable = true
                signingConfig = debug.signingConfig
            }
        }
    }
      

    Kotlin

    android {
        // ...
        // Note that your module name may have different name
        targetProjectPath = ":app"
        // Enable the benchmark to run separately from the app process
        experimentalProperties["android.experimental.self-instrumenting"] = true
    
        buildTypes {
            // declare a build type to match the target app's build type
            create("benchmark") {
                isDebuggable = true
                signingConfig = signingConfigs.getByName("debug")
            }
        }
    }
      

  3. Cambia todas las dependencias llamadas testImplementation o androidTestImplementation a implementation.
  4. Agrega una dependencia en la biblioteca de Macrobenchmark:
    implementation 'androidx.benchmark:benchmark-macro-junit4:1.1.0-beta03'
  5. Permite solo el buildType benchmark para este módulo. Después del bloque de android{}, pero antes del bloque dependencies{}, agrega lo siguiente:

    Groovy

    androidComponents {
        beforeVariants(selector().all()) {
            // enable only the benchmark buildType, since we only want to measure close to release performance
            enabled = buildType == 'benchmark'
        }
    }
      

    Kotlin

    androidComponents {
        beforeVariants {
            // enable only the benchmark buildType, since we only want to measure close to release performance
            it.enable = it.buildType == "benchmark"
        }
    }
      
  6. Simplifica la estructura del directorio.

    En un módulo com.android.test, hay un solo directorio del código fuente para todas las pruebas. Borra los otros directorios del código fuente, incluidos src/test y src/androidTest, ya que no se usan.

Cómo configurar la aplicación

A fin de obtener comparativas de una app (denominada el objetivo de la macrocomparativa), esta debe ser profileable para que se pueda leer información de seguimiento detallada. Puedes habilitar esta función en la etiqueta <application> del AndroidManifest.xml de la app:

<!-- enable profiling by macrobenchmark -->
<profileable
    android:shell="true"
    tools:targetApi="q" />

Configura la app de la que obtendrás comparativas lo más parecido a la versión de actualización (o producción) posible. 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

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 Macrobenchmark. 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

Configura la aplicación de 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.

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. Contiene un método measureRepeated que te permite detallar varias condiciones sobre cómo se debe 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

Cómo acceder manualmente a los archivos de registro

Si utilizas una versión previa de Android Studio (anterior a Arctic Fox 2020.3.1) o quieres usar la herramienta Perfetto para analizar un archivo de registro, necesitarás realizar 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 mediante 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 mediante 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.