Écrire une Macrobenchmark

La bibliothèque Macrobenchmark vous permet de tester des cas d'utilisation plus importants de votre application, y compris le démarrage de l'application et les manipulations complexes d'interface utilisateur comme le défilement d'un élément RecyclerView ou l'exécution d'animations. Si vous souhaitez tester des zones plus petites de votre code, consultez la bibliothèque Microbenchmark.

La bibliothèque génère des résultats d'analyse comparative dans la console Android Studio et dans un fichier JSON plus détaillé. Elle fournit également des fichiers de suivi que vous pouvez charger et analyser dans Android Studio.

Utilisez la bibliothèque Macrobenchmark dans un environnement d'intégration continue (CI), comme décrit dans Exécuter des analyses comparatives dans l'intégration continue.

Les profils de référence peuvent être générés à l'aide de Macrobenchmark. Suivez le guide ci-dessous pour configurer la bibliothèque Macrobenchmark puis créer un profil de référence.

Configuration du projet

Nous vous recommandons d'utiliser Macrobenchmark avec la dernière version d'Android Studio, car de nouvelles fonctionnalités de cette version de l'IDE s'intègrent à Macrobenchmark.

Configurer le module Macrobenchmark

Les analyses comparatives macros nécessitent un module com.android.test, distinct du code de votre application et chargé d'exécuter les tests qui mesurent votre application.

Un modèle est disponible dans Android Studio pour simplifier la configuration du module Macrobenchmark. Le modèle de module d'analyse comparative crée automatiquement un module dans votre projet pour mesurer l'application créée par un module d'application, y compris un exemple de benchmark de démarrage.

Pour créer un module à l'aide du modèle de module :

  1. Effectuez un clic droit sur votre projet ou votre module dans le panneau Project (Projet) d'Android Studio, puis cliquez sur New > Module (Nouveau > Module).

  2. Sélectionnez Benchmark (Analyse comparative) dans le volet Templates (Modèles).

  3. Vous pouvez personnaliser l'application cible (l'application à comparer), ainsi que le nom du package et du module du nouveau module d'analyse comparative macro.

  4. Cliquez sur Finish (Terminer).

Modèle de module d'analyse comparative

Configurer l'application

Pour faire l'analyse comparative d'une application (appelée cible de l'analyse comparative macro), cette application doit être profileable afin de lire des informations de trace détaillées sans nuire aux performances. L'assistant du module ajoute automatiquement la balise <profileable> au fichier AndroidManifest.xml de l'application.

Configurez l'application analysée pour qu'elle ressemble le plus possible à la version finale (ou à la version de production). Configurez-la comme non débogable, de préférence avec minimisation afin d'améliorer les performances. Pour ce faire, il est généralement nécessaire de créer une copie de la variante finale qui effectue les mêmes opérations, mais qui est signée localement à l'aide de clés de débogage. Vous pouvez également utiliser initWith pour déléguer cette opération à Gradle :

Groovy

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

    create("benchmark") {
        initWith(release)
        signingConfig = signingConfigs.getByName("debug")
        proguardFiles("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")
    }
}

Exécutez une synchronisation Gradle, ouvrez le panneau Build Variants (Variantes de compilation) sur la gauche, puis sélectionnez la variante d'analyse comparative de l'application et du module Macrobenchmark. Cette opération garantit que l'exécution de l'analyse comparative créera et testera la bonne variante de votre application :

Sélectionner une variante d'analyse comparative

(Facultatif) Configurer une application multimodule

Si votre application comporte plusieurs modules Gradle, assurez-vous que vos scripts de compilation savent quelle variante de compilation compiler. Sinon, le buildType benchmark nouvellement ajouté entraîne l'échec de la compilation et génère le message d'erreur suivant :

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

Vous pouvez résoudre le problème en ajoutant une propriété matchingFallbacks au buildType benchmark de vos modules :macrobenchmark et :app. Les autres modules Gradle peuvent avoir la même configuration qu'auparavant.

Groovy

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
}

Kotlin

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

    matchingFallbacks += listOf('release')
}

Lorsque vous sélectionnez les variantes de compilation dans votre projet, choisissez benchmark pour les modules :app et :macrobenchmark, et release pour tous les autres modules de votre application, comme indiqué dans l'image suivante :

Variantes de benchmark pour le projet multimodule avec des buildTypes de version et de benchmark sélectionnés

Pour en savoir plus, consultez la Gestion des dépendances selon les variantes.

(Facultatif) Configurer des types de produit

Si vous avez défini plusieurs types de produit dans votre application, vous devez configurer le module :macrobenchmark afin qu'il sache le type de produit de votre application à créer et sur lequel effectuer une analyse comparative. Sans cette configuration, vous risquez d'obtenir une erreur de compilation semblable à celle renvoyée en cas de plusieurs modules 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:
           ...

Pour ce guide, nous utilisons les deux types de produit de notre module :app (demo et production), comme vous pouvez le voir dans l'extrait suivant :

Groovy

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

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

Kotlin

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

Il existe deux façons de configurer une analyse comparative avec plusieurs types de produits :

Utiliser missingDimensionStrategy

La spécification de missingDimensionStrategy dans le defaultConfig du module :macrobenchmark indique au système de compilation de revenir au groupe de types. Vous devez spécifier les dimensions à utiliser si elles ne se trouvent pas dans le module. Dans l'exemple suivant, le type de produit production est utilisé comme la dimension par défaut :

Groovy

defaultConfig {
    missingDimensionStrategy "environment", "production"
}

Kotlin

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

De cette façon, le module :macrobenchmark ne peut créer et comparer que le type de produit spécifié, ce qui est utile si vous savez qu'un seul type de produit présente la configuration appropriée pour l'analyse comparative.

Définir les types de produit dans le module :macrobenchmark

Si vous souhaitez créer et comparer d'autres types de produit, vous devez les définir dans le module :macrobenchmark. Spécifiez-la de la même manière que dans le module :app, mais n'attribuez productFlavors qu'à une dimension. Aucun autre paramètre n'est requis :

Groovy

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

    production {
        dimension 'environment'
    }
}

Kotlin

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

Après avoir défini et synchronisé le projet, choisissez la variante de compilation souhaitée dans le volet Build Variants (Variantes de compilation) :

Variantes de benchmark du projet avec des types de produit montrant que la version et productionBenchmark sont sélectionnés

Pour en savoir plus, consultez la page Résoudre les erreurs de compilation liées à la correspondance des variantes.

Créer une classe Macrobenchmark

Les tests d'analyse comparative sont fournis via l'API de règle JUnit4 MacrobenchmarkRule dans la bibliothèque Macrobenchmark. Elle contient une méthode measureRepeated qui vous permet de spécifier différentes conditions d'exécution et d'analyse comparative de l'application cible.

Spécifiez au moins le packageName de l'application cible, les metrics que vous souhaitez mesurer et le nombre d'iterations que l'analyse comparative doit exécuter.

Kotlin

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

    @Test
    fun startup() = benchmarkRule.measureRepeated(
        packageName = TARGET_PACKAGE,
        metrics = listOf(StartupTimingMetric()),
        iterations = DEFAULT_ITERATIONS,
        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;
            }
        );
    }
}

Pour découvrir toutes les options permettant de personnaliser votre analyse comparative, consultez la section Personnaliser les analyses comparatives.

Exécuter l'analyse comparative

Exécutez le test depuis Android Studio pour mesurer les performances de votre application sur votre appareil. Vous pouvez exécuter les analyses comparatives de la même manière que tout autre @Test à l'aide de l'action "gouttière" à côté de la classe ou de la méthode de test, comme illustré dans l'image ci-dessous.

Exécuter Macrobenchmark avec une action "gouttière" à côté de la classe de test

Vous pouvez également exécuter toutes les analyses comparatives dans un module Gradle à partir de la ligne de commande en exécutant la commande connectedCheck :

./gradlew :macrobenchmark:connectedCheck

Pour effectuer un seul test, procédez comme suit :

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

Consultez la section Analyse comparative dans la CI pour savoir comment exécuter et surveiller des analyses comparatives dans l'intégration continue.

Résultats de l'analyse comparative

Une fois l'analyse comparative réussie, les métriques s'affichent directement dans Android Studio et affichent également les résultats pour l'utilisation de la CI dans un fichier JSON. Chaque itération mesurée capture une trace système distincte. Vous pouvez ouvrir ces traces de résultat en cliquant sur l'un des liens du volet Test Results (Résultats des tests), comme illustré ci-dessous.

Résultats du démarrage de Macrobenchmark

Une fois la trace chargée, Android Studio vous invite à sélectionner le processus à analyser. La sélection est préremplie avec le processus d'application cible :

Sélection du processus de trace dans Studio

Une fois le fichier de suivi chargé, Studio affiche les résultats dans l'outil Profileur de processeur :

Trace dans Studio

Les rapports JSON et les traces de profilage sont également copiés automatiquement depuis l'appareil vers l'hôte. Ils sont écrits sur la machine hôte à l'emplacement suivant :

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

Accéder manuellement aux fichiers de suivi

Si vous souhaitez analyser un fichier de suivi à l'aide de l'outil Perfetto, quelques étapes supplémentaires sont nécessaires. Perfetto vous permet d'inspecter tous les processus de l'appareil pendant la trace, tandis que le Profileur de processeur d'Android Studio limite l'inspection à un seul processus.

Si vous appelez les tests à partir d'Android Studio ou à l'aide de la ligne de commande Gradle, les fichiers de suivi sont automatiquement copiés depuis l'appareil vers l'hôte. Ils sont écrits sur la machine hôte à l'emplacement suivant :

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

Une fois le fichier de suivi dans votre système hôte, vous pouvez l'ouvrir dans Android Studio en sélectionnant File > Open (Fichier > Ouvrir) dans le menu. Cela permet d'afficher la vue de l'outil de profilage présentée dans la section précédente.

Erreurs de configuration

Si l'application est mal configurée (débogable ou non profilable), Macrobenchmark renvoie une erreur au lieu de signaler une mesure incorrecte ou incomplète. Vous pouvez supprimer ces erreurs à l'aide de l'argument androidx.benchmark.suppressErrors.

Des erreurs sont également générées lorsque vous tentez de mesurer un émulateur ou sur un appareil à faible batterie, car cela peut compromettre la disponibilité principale et la vitesse d'horloge.

Personnaliser les analyses comparatives

La fonction measureRepeated accepte différents paramètres ayant une influence sur les métriques collectées par la bibliothèque, sur la manière dont votre application est démarrée et compilée ou sur le nombre d'itérations que l'analyse comparative va exécuter.

Capturer les métriques

Les métriques sont le principal type d'informations extraites de vos analyses comparatives. Les options disponibles sont StartupTimingMetric, FrameTimingMetric et TraceSectionMetric. Pour en savoir plus à ce sujet, consultez la page Capturer les métriques.

Améliorer les données de trace avec des événements personnalisés

Il peut être utile d'instrumenter votre application avec des événements de trace personnalisés, qui apparaissent dans le reste du rapport de trace et peuvent aider à identifier les problèmes spécifiques à votre application. Pour en savoir plus sur la création d'événements de trace personnalisés, consultez le guide Définir des événements personnalisés.

Paramètre CompilationMode

Les analyses comparatives macros peuvent spécifier un paramètre CompilationMode, qui définit la part de l'application qui doit être précompilée à partir du bytecode DEX (format bytecode d'un fichier APK) sur le code machine (semblable à C++ précompilé).

Par défaut, les analyses comparatives macros sont exécutées avec CompilationMode.DEFAULT, qui installe un profil de référence (si disponible) sur Android version 7 (niveau 24 d'API) ou ultérieure. Si vous utilisez Android version 6 (niveau 23 d'API) ou antérieure, le mode compilation compile intégralement l'APK en tant que comportement système par défaut.

Vous pouvez installer un profil de référence si l'application cible contient à la fois un profil de référence et la bibliothèque ProfileInstaller.

Sur Android version 7 et ultérieures, vous pouvez personnaliser le CompilationMode pour influer sur la quantité de précompilation sur l'appareil et simuler différents niveaux de compilation en amont ou de mise en cache JIT. Voir CompilationMode.Full, CompilationMode.Partial et CompilationMode.None.

Cette fonctionnalité repose sur des commandes de compilation ART. Chaque analyse comparative efface les données de profil avant de commencer pour éviter toute interférence entre les analyses comparatives.

Mode de démarrage

Pour démarrer une activité, vous pouvez transmettre un mode de démarrage prédéfini (COLD, WARM ou HOT) qui modifie le mode de lancement de l'activité et l'état du processus au début du test.

Pour en savoir plus sur les types de démarrage, consultez les documents de démarrage Android Vitals.

Exemples

Un exemple de projet est disponible sur GitHub dans le dépôt android/performance-samples.

Envoyer un commentaire

Pour signaler des problèmes ou envoyer des demandes de fonctionnalité pour Jetpack Macrobenchmark, consultez l'outil public Issue Tracker.