Benchmark nell'integrazione continua

Puoi eseguire benchmark in integrazione continua (CI) per monitorare le prestazioni nel tempo e riconoscere regressioni o miglioramenti delle prestazioni prima ancora che l'app venga rilasciata. Questa pagina fornisce informazioni di base sul benchmarking in CI.

Prima di iniziare a utilizzare il benchmarking nella CI, valuta le differenze di acquisizione e valutazione dei risultati rispetto ai test normali.

Risultati parziali

Sebbene i benchmark siano test strumentati, i risultati non indicano semplicemente che il test è stato superato o meno. I benchmark forniscono misurazioni dei tempi per il dispositivo su cui vengono eseguiti. I grafici dei risultati nel tempo consentono di monitorare le variazioni e osservare il rumore nel sistema di misurazione.

Usa dispositivi reali

Eseguire benchmark su dispositivi Android fisici. Nonostante possano essere eseguiti su emulatori, sconsigliamo vivamente di utilizzarli perché non offrono un'esperienza utente realistica e forniscono numeri associati al sistema operativo host e alle funzionalità hardware. Potresti utilizzare dispositivi reali o un servizio che ti consenta di eseguire test su dispositivi reali, come Firebase Test Lab.

Esegui i benchmark

L'esecuzione dei benchmark all'interno della pipeline CI potrebbe essere diversa da quella locale da Android Studio. A livello locale, in genere esegui i test di integrazione Android con un'attività Gradle connectedCheck. Questa attività crea automaticamente l'APK e l'APK di test, quindi esegue i test sui dispositivi connessi al server CI. Quando viene eseguito in CI, solitamente questo flusso deve essere suddiviso in fasi separate.

Crea

Per la libreria Microbenchmark, esegui l'attività Gradle assemble[VariantName]AndroidTest, che crea l'APK di test contenente sia il codice dell'applicazione sia il codice testato.

In alternativa, la libreria Macrobenchmark richiede di creare separatamente l'APK di destinazione e l'APK di test. Pertanto, esegui le attività :app:assemble[VariantName] e :macrobenchmark:assemble[VariantName] Gradle.

Installa ed esegui

In genere, questi passaggi vengono eseguiti senza dover eseguire attività Gradle. Tieni presente che possono essere astratte a seconda che utilizzi o meno un servizio che ti consente di eseguire test su dispositivi reali.

Per l'installazione, utilizza il comando adb install e specifica l'APK di test o l'APK di destinazione.

Esegui il comando adb shell am instrument per eseguire tutti i benchmark:

adb shell am instrument -w com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner

Quando usi la libreria Macrobenchmark, usa normale androidx.test.runner.AndroidJUnitRunner come runner della strumentazione.

Puoi passare gli stessi argomenti di strumentazione della configurazione Gradle utilizzando l'argomento -e. Per tutte le opzioni di argomenti di strumentazione, consulta Argomenti di strumentazione Microbenchmark o Aggiungere argomenti di strumentazione per Macrobenchmark.

Ad esempio, puoi impostare l'argomento dryRunMode per eseguire microbenchmark nell'ambito del processo di verifica delle richieste di pull. Con questo flag abilitato, i microservizi vengono eseguiti in un solo loop, verificando che siano eseguiti correttamente senza richiedere troppo tempo.

adb shell am instrument -w -e "androidx.benchmark.dryRunMode.enable" "true" com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner

Per maggiori informazioni su come eseguire i test di strumentazione dalla riga di comando, vedi Eseguire test con ADB.

Blocca orologi

Il plug-in Gradle Microbenchmark fornisce il comando ./gradlew lockClocks per bloccare i clock della CPU di un dispositivo rooted. Ciò è utile per garantire stabilità quando hai accesso a dispositivi rooted, come le build "userdebug". Puoi replicare con lo script shell lockClocks.sh, disponibile nell' origine della libreria.

Puoi eseguire lo script direttamente da un host Linux o Mac oppure eseguire il push al dispositivo con alcuni comandi adb:

adb push path/lockClocks.sh /data/local/tmp/lockClocks.sh
adb shell /data/local/tmp/lockClocks.sh
adb shell rm /data/local/tmp/lockClocks.sh

Se esegui lo script shell direttamente su un host, questo invia i comandi a un dispositivo connesso.

Per ulteriori informazioni sul motivo per cui è utile bloccare i clock della CPU, scopri come ottenere benchmark coerenti.

Raccogli i risultati

Le librerie di benchmarking forniscono le misurazioni in JSON, insieme alle tracce di profilazione su una directory sul dispositivo Android dopo ogni esecuzione di benchmark. La libreria Macrobenchmark genera più file di traccia perfetti: uno per iterazione misurata di ogni loop MacrobenchmarkRule.measureRepeated. Microbenchmark, tuttavia, crea un solo file di traccia per tutte le iterazioni di BenchmarkRule.measureRepeated. Anche i file di traccia di profilazione vengono inviati a questa stessa directory.

Salva e individua i file

Se esegui i benchmark con Gradle, questi file vengono copiati automaticamente nella directory di output del computer host in build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/.

Se l'esecuzione avviene direttamente con il comando adb, devi estrarre i file manualmente. Per impostazione predefinita, i report vengono salvati sul dispositivo nella directory dei contenuti multimediali della memoria esterna dell'app testata. Per praticità, la libreria stampa il percorso del file in Logcat. Tieni presente che la cartella di output può essere diversa a seconda della versione di Android su cui sono in esecuzione i benchmark.

Benchmark: writing results to /storage/emulated/0/Android/media/com.example.macrobenchmark/com.example.macrobenchmark-benchmarkData.json

Puoi anche configurare la località in cui vengono salvati i report di benchmark sul dispositivo utilizzando l'argomento strumentazione additionalTestOutputDir. La tua app deve poter scrivere questa cartella.

adb shell am instrument -w -e additionalTestOutputDir /sdcard/Download/ com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner

Su Android 10 (livello API 29) e versioni successive, per impostazione predefinita i test dell'app vengono eseguiti in una sandbox di archiviazione, il che impedisce all'app di accedere ai file al di fuori della directory specifica dell'app. Per poter eseguire il salvataggio in una directory globale, ad esempio /sdcard/Download, passa il seguente argomento di strumentazione:

-e no-isolated-storage true

Devi inoltre consentire esplicitamente le opzioni di archiviazione legacy nel file manifest del benchmark:

<application android:requestLegacyExternalStorage="true" ... >

Per ulteriori informazioni, consulta Disattivare temporaneamente l'archiviazione con ambito.

Recupera i file

Per recuperare i file generati dal dispositivo, utilizza il comando adb pull, che esegue il pull del file specificato nella directory corrente sul tuo host:

adb pull /storage/emulated/0/Android/media/com.example.macrobenchmark/com.example.macrobenchmark-benchmarkData.json

Per recuperare tutti i benchmarkData da una cartella specificata, controlla il seguente snippet:

# The following command pulls all files ending in -benchmarkData.json from the directory
# hierarchy starting at the root /storage/emulated/0/Android.
adb shell find /sdcard/Download -name "*-benchmarkData.json" | tr -d '\r' | xargs -n1 adb pull

I file di traccia (.trace o .perfetto-trace) vengono salvati nella stessa cartella del file benchmarkData.json e puoi raccoglierli nello stesso modo.

Esempio di dati di benchmark

Le librerie di benchmark generano file JSON contenenti informazioni sul dispositivo su cui stavano eseguendo i benchmark e sui benchmark effettivi eseguiti. Il seguente snippet rappresenta il file JSON generato:

{
    "context": {
        "build": {
            "brand": "google",
            "device": "blueline",
            "fingerprint": "google/blueline/blueline:12/SP1A.210812.015/7679548:user/release-keys",
            "model": "Pixel 3",
            "version": {
                "sdk": 31
            }
        },
        "cpuCoreCount": 8,
        "cpuLocked": false,
        "cpuMaxFreqHz": 2803200000,
        "memTotalBytes": 3753299968,
        "sustainedPerformanceModeEnabled": false
    },
    "benchmarks": [
        {
            "name": "startup",
            "params": {},
            "className": "com.example.macrobenchmark.startup.SampleStartupBenchmark",
            "totalRunTimeNs": 4975598256,
            "metrics": {
                "timeToInitialDisplayMs": {
                    "minimum": 347.881076,
                    "maximum": 347.881076,
                    "median": 347.881076,
                    "runs": [
                        347.881076
                    ]
                }
            },
            "sampledMetrics": {},
            "warmupIterations": 0,
            "repeatIterations": 3,
            "thermalThrottleSleepSeconds": 0
        }
    ]
}

Risorse aggiuntive