Écrire un 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. Cette page vous explique comment configurer la bibliothèque Macrobenchmark.

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 Benchmark dans l'intégration continue.

Vous pouvez utiliser Macrobenchmark pour générer des profils de référence. Commencez par configurer la bibliothèque Macrobenchmark, puis vous pouvez 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 pour les fonctionnalités de l'IDE qui s'intègrent à Macrobenchmark.

Configurer le module Macrobenchmark

Les macrobenchmarks 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). 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.

  3. Cliquez sur Finish (Terminer).

Modèle de module d'analyse comparative

Figure 1 : Modèle de module d'analyse comparative

Configurer l'application

Pour comparer une application (appelée cible du Macrobenchmark), elle doit être profileable, ce qui permet de lire les informations de trace détaillées sans affecter les performances L'assistant du module ajoute automatiquement la balise <profileable> au fichier AndroidManifest.xml de l'application.

Assurez-vous que l'application cible inclut ProfilerInstaller 1.3 ou version ultérieure, dont la bibliothèque Macrobenchmark a besoin pour activer la capture de profil, la réinitialisation et la suppression du cache du nuanceur.

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 :

Kotlin

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

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

Groovy

buildTypes {
    getByName("release") {
        isMinifyEnabled = true
        isShrinkResources = true
        proguardFiles(
            getDefaultProguardFile("proguard-android-optimize.txt"),
            "proguard-rules.pro"
        )
        // In real app, this would use its own release keystore
        signingConfig = signingConfigs.getByName("debug")
    }
}

Pour vous assurer que l'exécution de l'analyse comparative crée et teste la bonne variante de votre application, comme illustré dans la figure 2, procédez comme suit :

  1. Effectuez une synchronisation Gradle.
  2. Ouvrez le panneau Variantes de compilation.
  3. Sélectionnez la variante d'analyse comparative de l'application et du module Macrobenchmark.

Sélectionner une variante d&#39;analyse comparative

Figure 2. Sélectionnez la variante d'analyse comparative.

(Facultatif) Configurer une application multimodule

Si votre application comporte plusieurs modules Gradle, assurez-vous que vos scripts de compilation sachent quelle variante compiler. Ajoutez la propriété matchingFallbacks au type de compilation benchmark de vos modules :macrobenchmark et :app. Les autres modules Gradle peuvent avoir la même configuration qu'auparavant.

Kotlin

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

    matchingFallbacks += listOf("release")
}

Groovy

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
}

Sans cela, le type de compilation 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.
      ...

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 la figure 3 :

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

Figure 3 : Variantes de benchmark pour le projet multimodule avec des types de compilation de version et de benchmark sélectionnés

Pour en savoir plus, consultez Utiliser la gestion des dépendances basée sur 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.

Les exemples de cette page utilisent les deux types de produit dans le module :app : demo et production, comme indiqué dans l'extrait de code suivant :

Kotlin

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

Groovy

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

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

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

Les deux sections suivantes expliquent comment 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. Spécifiez les dimensions à utiliser si vous ne les trouvez pas dans le module. Dans l'exemple suivant, le type de produit production est utilisé comme la dimension par défaut :

Kotlin

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

Groovy

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, définissez-les dans le module :macrobenchmark. Spécifiez-les de la même manière que dans le module :app, mais n'attribuez productFlavors qu'à un dimension. Aucun autre paramètre n'est requis.

Kotlin

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

Groovy

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

    production {
        dimension 'environment'
    }
}

Après avoir défini et synchronisé le projet, choisissez la variante de compilation appropriée dans le volet Variantes de compilation, comme illustré dans la figure 4 :

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

Figure 4 : Variantes de benchmark du projet avec les types de produit affichant "productionBenchmark" et "release".

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 le benchmark 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 toutes les options de personnalisation du benchmark, consultez la section Personnaliser les analyses comparatives.

Exécuter le benchmark

Exécutez le test depuis Android Studio pour mesurer les performances de votre application sur votre appareil. Vous pouvez exécuter les benchmarks de la même manière que tout autre @Test à l'aide de la gouttière située en regard de votre classe ou méthode de test, comme illustré dans la figure 5.

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

Figure 5 : 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 exécuter un seul test, procédez comme suit :

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

Pour en savoir plus sur l'exécution et la surveillance des benchmarks dans l'intégration continue, consultez la page Benchmark dans l'intégration continue.

Résultats du benchmark

Une fois le benchmark réussi, 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 résultats de trace en cliquant sur les liens du volet Test Results (Résultats des tests), comme illustré dans la figure 6 :

Résultats du démarrage de Macrobenchmark

Figure 6 : 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, comme illustré dans la figure 7 :

Sélection du processus de trace dans Studio

Figure 7 : 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

Figure 8 : 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, des é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 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.

Macrobenchmark renvoie également des erreurs lorsque vous tentez de mesurer un émulateur ou sur un appareil dont la batterie est faible, ce qui peut compromettre la disponibilité principale et la vitesse de l'horloge.

Personnaliser les benchmarks

La fonction measureRepeated accepte différents paramètres qui influent sur les métriques collectées par la bibliothèque, sur le démarrage et la compilation de votre application ou sur le nombre d'itérations exécutées par le benchmark.

Capturer les métriques

Les métriques sont le principal type d'informations extraites de vos analyses comparatives. Les métriques suivantes sont disponibles :

Pour en savoir plus sur les métriques, consultez Capturer les métriques Macrobenchmark.

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.

CompilationMode

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

Par défaut, les macrobenchmarks sont exécutés avec CompilationMode.DEFAULT, qui installe un profil de référence (si disponible) sur Android 7 (niveau d'API 24) ou version ultérieure. Si vous utilisez Android version 6 (niveau 23 d'API) ou antérieure, le mode de 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 7 et versions 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. Consultez CompilationMode.Full, CompilationMode.Partial, CompilationMode.None et CompilationMode.Ignore.

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

StartupMode

Pour effectuer une activité, vous pouvez transmettre un mode de démarrage prédéfini : COLD, WARM ou HOT. Ce paramètre 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 Temps de démarrage de l'application.

Exemples

Un exemple de projet est disponible dans l'exemple Macrobenchmark du dépôt sur GitHub.

Envoyer des commentaires

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