Scrivi un Macrobenchmark

Utilizza la libreria Macrobenchmark per testare casi d'uso più ampi della tua app, tra cui l'avvio dell'app e complesse manipolazioni dell'interfaccia utente, come lo scorrimento di un RecyclerView o l'esecuzione di animazioni. Se vuoi testare aree più piccole del codice, consulta Libreria Microbenchmark. Questa pagina mostra come impostare la libreria Macrobenchmark.

La libreria genera i risultati del benchmarking sia nella console di Android Studio sia in un file JSON con ulteriori dettagli. Fornisce inoltre file di traccia che puoi caricare e analizzare in Android Studio.

Utilizza la libreria Macrobenchmark in un ambiente di integrazione continua (CI), come descritto in Benchmark nell'integrazione continua.

Puoi utilizzare Macrobenchmark per generare profili di riferimento. Innanzitutto, configura la libreria Macrobenchmark, quindi puoi creare un profilo di riferimento.

Configurazione del progetto

Ti consigliamo di utilizzare Macrobenchmark con la versione più recente di Android Studio per le funzionalità dell'IDE che si integrano con Macrobenchmark.

Configurare il modulo Macrobenchmark

I macrobenchmark richiedono un modulo com.android.test, separato dal codice dell'app, responsabile dell'esecuzione dei test che misurano la tua app.

In Android Studio è disponibile un modello per semplificare la configurazione del modulo Macrobenchmark. Il modello di modulo di benchmarking crea automaticamente un modulo nel progetto per misurare l'app creata da un modulo dell'app, incluso un benchmark di esempio per l'avvio.

Per utilizzare il modello di modulo per creare un nuovo modulo, segui questi passaggi:

  1. Fai clic con il pulsante destro del mouse sul progetto o modulo nel riquadro Progetto in Android Studio e seleziona Nuovo > Modulo.

  2. Seleziona Benchmark dal riquadro Modelli. Puoi personalizzare l'app di destinazione, ovvero l'app da sottoporre a benchmark, nonché il nome del pacchetto e del modulo per il nuovo modulo Macrobenchmark.

  3. Fai clic su Fine.

Modello di modulo Benchmark

Figura 1. Modello del modulo Benchmark.

Configura l'app

Per eseguire il benchmark di un'app, nota come target di Macrobenchmark, deve essere profileable, che consente la lettura di informazioni di traccia dettagliate senza influire sulle prestazioni. La procedura guidata per i moduli aggiunge automaticamente il tag <profileable> al file AndroidManifest.xml dell'app.

Assicurati che l'app di destinazione includa ProfilerInstaller 1.3 o versioni successive, necessarie alla libreria di Macrobenchmark per abilitare l'acquisizione, la reimpostazione e la cancellazione della cache del profilo.

Configura l'app di benchmark il più vicino possibile alla versione di release o di produzione. Configuralo come non eseguirne il debug e preferibilmente con la minimizzazione attiva, che migliora le prestazioni. In genere, puoi farlo creando una copia della variante della release, che ha le stesse prestazioni, ma è firmata localmente con chiavi di debug. In alternativa, puoi utilizzare initWith per indicare a Gradle di farlo per te:

Kotlin

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

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

Trendy

buildTypes {
    val release = 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")
    }

    create("benchmark") {
        initWith(release)
        signingConfig = signingConfigs.getByName("debug")
        proguardFiles("benchmark-rules.pro")
    }
}

Per assicurarti che l'esecuzione del benchmark crei e test la variante corretta della tua app, come mostrato nella Figura 2:

  1. Eseguire una sincronizzazione con Gradle.
  2. Apri il riquadro Crea varianti.
  3. Seleziona la variante benchmark dell'app e del modulo Macrobenchmark.

Seleziona variante di benchmark

Figura 2. Seleziona la variante benchmark.

(Facoltativo) Configurare un'app multi-modulo

Se la tua app ha più di un modulo Gradle, assicurati che i tuoi script di build sappiano quale variante di build compilare. Aggiungi la proprietà matchingFallbacks al tipo di build benchmark dei moduli :macrobenchmark e :app. Gli altri moduli Gradle possono avere la stessa configurazione di prima.

Kotlin

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

    matchingFallbacks += listOf("release")
}

Trendy

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
}

Senza questo parametro, il tipo di build benchmark appena aggiunto provoca un errore della build e restituisce il seguente messaggio di errore:

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

Quando selezioni le varianti di build nel progetto, scegli benchmark per i moduli :app e :macrobenchmark e release per tutti gli altri moduli presenti nella tua app, come mostrato nella figura 3:

Varianti di benchmark per un progetto multi-modulo con i tipi di build di release e benchmark selezionati

Figura 3. Varianti di benchmark per il progetto con più moduli con i tipi di build di release e benchmark selezionati.

Per saperne di più, consulta Utilizzare la gestione delle dipendenze sensibile alle varianti.

(Facoltativo) Configurare i sapori dei prodotti

Se nella tua app hai impostato più versioni di prodotto, configura il modulo :macrobenchmark in modo che sappia quale versione dell'app creare e come benchmark.

Gli esempi in questa pagina utilizzano i due gusti di prodotto nel modulo :app: demo e production, come mostrato nel seguente snippet:

Kotlin

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

Trendy

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

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

Senza questa configurazione, potresti ricevere un errore di compilazione simile a quello con più moduli 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:
           ...

Le due sezioni seguenti spiegano come configurare il benchmarking con più varianti di prodotti.

Utilizzare la strategiaDimensione mancante

Se specifichi missingDimensionStrategy nel defaultConfig del modulo :macrobenchmark, indichi al sistema di compilazione di utilizzare la dimensione versione di riserva. Specifica quali dimensioni utilizzare se non le trovi nel modulo. Nell'esempio seguente, la versione production viene utilizzata come dimensione predefinita:

Kotlin

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

Trendy

defaultConfig {
    missingDimensionStrategy "environment", "production"
}

In questo modo, il modulo :macrobenchmark è in grado di creare e confrontare solo il sapore di prodotto specificato, il che è utile se sai che solo un gusto di prodotto ha la configurazione corretta per il benchmark.

Definire i gusti dei prodotti nel modulo :macrobenchmark

Se vuoi creare ed eseguire il benchmark di altre versioni di prodotto, definiscile nel modulo :macrobenchmark. Specificalo in modo simile nel modulo :app, ma assegna solo productFlavors a un dimension. Non sono necessarie altre impostazioni:

Kotlin

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

Trendy

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

    production {
        dimension 'environment'
    }
}

Dopo aver definito e sincronizzato il progetto, scegli la variante di build pertinente dal riquadro Varianti build, come mostrato nella figura 4:

Benchmark le varianti per il progetto con versioni di prodotto che mostrano
productionBenchmark e release
selezionate

Figura 4. Confronta le varianti del progetto con le versioni di prodotto in cui sono selezionate "productionBenchmark" e "release".

Per saperne di più, consulta Risolvere gli errori di build relativi alla corrispondenza delle varianti.

Creazione di una classe macrobenchmark

I test di benchmark vengono forniti tramite l'API per la regola JUnit4 MacrobenchmarkRule nella libreria Macrobenchmark. Contiene un metodo measureRepeated che consente di specificare varie condizioni per l'esecuzione e il benchmark dell'app di destinazione.

Devi specificare almeno il packageName dell'app target, gli elementi metrics da misurare e il numero di iterations che deve essere eseguito dal benchmark.

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;
            }
        );
    }
}

Per tutte le opzioni sulla personalizzazione del benchmark, consulta la sezione Personalizzare i benchmark.

Esegui il benchmark

Esegui il test da Android Studio per misurare le prestazioni della tua app sul dispositivo. Puoi eseguire i benchmark nello stesso modo in cui esegui qualsiasi altro @Test utilizzando l'azione gutter accanto alla classe o al metodo di test, come mostrato nella figura 5.

Esegui macrobenchmark con azione gutter accanto alla classe di test

Figura 5. Esegui Macrobenchmark con l'azione gutter accanto alla classe di test.

Puoi anche eseguire tutti i benchmark in un modulo Gradle dalla riga di comando eseguendo il comando connectedCheck:

./gradlew :macrobenchmark:connectedCheck

Puoi eseguire un singolo test eseguendo questo comando:

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

Consulta Benchmark nell'integrazione continua per informazioni su come eseguire e monitorare i benchmark nell'integrazione continua.

Risultati dei benchmark

Dopo un'esecuzione del benchmark riuscita, le metriche vengono visualizzate direttamente in Android Studio e vengono restituite per l'utilizzo CI in un file JSON. Ogni iterazione misurata acquisisce una traccia di sistema separata. Puoi aprire i risultati delle tracce facendo clic sui link nel riquadro Risultati del test, come mostrato nella figura 6:

Risultati dell&#39;avvio
di Macrobenchmark

Figura 6. Risultati di avvio di Macrobenchmark.

Quando la traccia viene caricata, Android Studio ti chiede di selezionare il processo da analizzare. La selezione viene precompilata con il processo dell'app di destinazione, come mostrato nella Figura 7:

Selezione del processo
della traccia di Studio

Figura 7. Selezione del processo della traccia di Studio.

Una volta caricato il file di traccia, Studio mostra i risultati nello strumento CPU profiler:

Studio
Trace

Figura 8. Traccia di Studio.

Anche i report JSON e le eventuali tracce di profilazione vengono copiati automaticamente dal dispositivo all'host. Questi dati sono scritti sulla macchina host nella seguente posizione:

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

Accedere manualmente ai file di traccia

Se vuoi usare lo strumento Perfetto per analizzare un file di traccia, devi eseguire ulteriori passaggi. Perfetto ti consente di controllare tutti i processi che si verificano sul dispositivo durante la traccia, mentre il profiler della CPU di Android Studio limita l'ispezione a un singolo processo.

Se richiami i test da Android Studio o dalla riga di comando Gradle, i file di traccia vengono copiati automaticamente dal dispositivo all'host. Questi dati vengono scritti sulla macchina host nella seguente posizione:

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

Una volta trovato il file di traccia nel sistema host, puoi aprirlo in Android Studio selezionando File > Apri nel menu. Mostra la visualizzazione dello strumento Profiler nella sezione precedente.

Errori di configurazione

Se l'app non è configurata correttamente (debug o non profilabile), Macrobenchmark restituisce un errore anziché segnalare una misurazione errata o incompleta. Puoi eliminare questi errori con l'argomento androidx.benchmark.suppressErrors.

Macrobenchmark restituisce anche errori quando si cerca di misurare un emulatore o su un dispositivo con batteria in esaurimento, che potrebbero compromettere la disponibilità dei core e la velocità dell'orologio.

Personalizzare i benchmark

La funzione measureRepeated accetta vari parametri che influiscono sulle metriche raccolte dalla libreria, sul modo in cui la tua app viene avviata e compilata o sul numero di iterazioni eseguite dal benchmark.

Acquisisci le metriche

Le metriche sono il tipo principale di informazioni estratte dai benchmark. Sono disponibili le seguenti metriche:

Per ulteriori informazioni sulle metriche, consulta Acquisizione delle metriche di Macrobenchmark.

Migliora i dati di traccia con gli eventi personalizzati

Può essere utile configurare la tua app con eventi di traccia personalizzati, che vengono visualizzati insieme al resto del report sulle tracce e possono aiutarti a segnalare problemi specifici della tua app. Per scoprire di più sulla creazione di eventi di traccia personalizzati, consulta Definire eventi personalizzati.

Modalità Compilation

I Macrobenchmark possono specificare un valore CompilationMode, che definisce la quantità di app che deve essere precompilata dal bytecode DEX (il formato bytecode all'interno di un APK) al codice macchina (simile al C++ precompilato).

Per impostazione predefinita, i Macrobenchmark vengono eseguiti con CompilationMode.DEFAULT, che installa un profilo di riferimento, se disponibile, su Android 7 (livello API 24) e versioni successive. Se utilizzi Android 6 (livello API 23) o versioni precedenti, la modalità di compilazione compila completamente l'APK come comportamento di sistema predefinito.

Puoi installare un profilo di riferimento se l'app di destinazione contiene sia un profilo di riferimento sia la libreria ProfileInstaller.

Su Android 7 e versioni successive, puoi personalizzare CompilationMode in modo da influire sulla quantità di precompilazione sul dispositivo in modo da imitare diversi livelli di compilazione AOT o di memorizzazione nella cache JIT. Vedi CompilationMode.Full, CompilationMode.Partial, CompilationMode.None e CompilationMode.Ignore.

Questa funzionalità è basata sui comandi di compilazione ART. Ogni benchmark cancella i dati del profilo prima di iniziare, per garantire la non interferenza tra i benchmark.

Modalità Startup

Per avviare un'attività, puoi superare una modalità di avvio predefinita: COLD, WARM o HOT. Questo parametro modifica il modo in cui viene avviata l'attività e lo stato del processo all'inizio del test.

Per scoprire di più sui tipi di avvio, vedi Tempo di avvio dell'app.

Samples

Un progetto di esempio è disponibile nell'esempio di Macrobenchmark del repository su GitHub.

Fornire feedback

Per segnalare problemi o inviare richieste di funzionalità per Jetpack Macrobenchmark, consulta il tracker pubblico dei problemi.