Utwórz makroporównawczy

Użyj biblioteki Macroporównanie do testowania większych przypadków użycia aplikacji, w tym uruchamiania aplikacji i skomplikowanych manipulacji interfejsem, takich jak przewijanie obszaru RecyclerView czy uruchamianie animacji. Jeśli chcesz testować mniejsze obszary kodu, skorzystaj z biblioteki Microbenchmark. Tutaj pokazujemy, jak skonfigurować bibliotekę Macroporównanie.

Biblioteka generuje wyniki testów porównawczych zarówno do konsoli Android Studio, jak i w pliku JSON z bardziej szczegółowymi informacjami. Zawiera też pliki śledzenia, które można wczytać i przeanalizować w Android Studio.

Użyj biblioteki makrporównawczych w środowisku ciągłej integracji (CI) zgodnie z opisem w sekcji Analiza porównawcza w ciągłej integracji.

Za pomocą Analizy porównawczej możesz wygenerować profile bazowe. Najpierw skonfiguruj bibliotekę Macroporównanie, a następnie możesz utworzyć profil podstawowy.

Konfigurowanie projektu

W przypadku funkcji IDE, które integrują się z Macrobenchmark, zalecamy korzystanie z Macroporównania w najnowszej wersji Android Studio.

Konfigurowanie modułu Makroporównań

Analiza porównawcza makr wymaga modułu com.android.test – niezależnego od kodu aplikacji – który odpowiada za uruchamianie testów na temat aplikacji.

W Android Studio dostępny jest szablon, który upraszcza konfigurację modułu Macrobenchmark. Szablon modułu analizy porównawczej automatycznie tworzy w Twoim projekcie moduł do pomiaru aplikacji skompilowanej przez moduł aplikacji, w tym przykładową analizę porównawczą.

Aby użyć szablonu do utworzenia nowego modułu:

  1. Kliknij prawym przyciskiem myszy projekt lub moduł w panelu Projekt w Android Studio i wybierz Nowy > Moduł.

  2. W panelu Szablony kliknij Analiza porównawcza. Możesz dostosować aplikację docelową (czyli aplikację do analizy porównawczej) oraz nazwę pakietu i modułu na potrzeby nowego modułu Macroporównanie.

  3. Kliknij Zakończ.

Szablon modułu analizy porównawczej

Rysunek 1. Szablon modułu analizy porównawczej.

Konfigurowanie aplikacji

Aby przeprowadzić test porównawczy aplikacji – tzw. celu testu porównawczego makr, musi ona mieć typ profileable, co umożliwia odczytywanie szczegółowych informacji z śladu bez wpływu na wydajność. Kreator modułu automatycznie dodaje tag <profileable> do pliku AndroidManifest.xml aplikacji.

Upewnij się, że aplikacja docelowa zawiera pakiet ProfilerInstaller w wersji 1.3 lub nowszej, którego biblioteka Macroporównanie jest potrzebna, aby umożliwić przechwytywanie profilu, resetowanie i czyszczenie pamięci podręcznej narzędzia cieniowania.

Skonfiguruj aplikację z testu porównawczego jak najbliżej wersji produkcyjnej lub wersji produkcyjnej. Skonfiguruj go jako bez możliwości debugowania, a najlepiej z włączoną minifikacją, co zwiększa wydajność. Zwykle robi się to przez utworzenie kopii wariantu wersji. Ta funkcja działa tak samo, ale jest podpisywana lokalnie kluczami debugowania. Możesz też użyć polecenia initWith, aby polecić Gradle wykonanie tej czynności za Ciebie:

Kotlin

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

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

Odlotowy

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

Aby mieć pewność, że w ramach testu porównawczego zostaną zarówno kompilacje, jak i przetestowanie właściwej wersji aplikacji (jak widać na Rysunku 2), wykonaj te czynności:

  1. Przeprowadź synchronizację z Gradle.
  2. Otwórz panel Tworzenie wariantów.
  3. Wybierz wersję porównawczą aplikacji i modułu Macroporównanie.

Wybierz wariant porównania

Rysunek 2. Wybierz wariant porównawczy.

(Opcjonalnie) Skonfiguruj aplikację składającą się z wielu modułów

Jeśli aplikacja ma więcej niż 1 moduł Gradle, upewnij się, że skrypty kompilacji wiedzą, który wariant kompilacji ma być skompilowany. Dodaj właściwość matchingFallbacks do typu kompilacji benchmark modułów :macrobenchmark i :app. Pozostałe moduły Gradle mogą mieć taką samą konfigurację jak poprzednio.

Kotlin

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

    matchingFallbacks += listOf("release")
}

Odlotowy

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
}

Bez niego nowo dodany typ kompilacji benchmark powoduje błąd kompilacji i wyświetla ten komunikat o błędzie:

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

Wybierając warianty kompilacji w projekcie, wybierz benchmark dla modułów :app i :macrobenchmark oraz release dla pozostałych modułów, które masz w aplikacji, jak widać na rysunku 3:

Testowanie wariantów dla projektu składającego się z wielu modułów z wybranymi
typami kompilacji wersji i testów porównawczych

Rysunek 3. Testowanie wariantów dla projektu składającego się z wielu modułów z wybranymi typami kompilacji w wersji produkcyjnej i porównawczych.

Więcej informacji znajdziesz w artykule Korzystanie z zarządzania zależnościami zależnymi od wariantów.

(Opcjonalnie) Skonfiguruj smaki produktów

Jeśli w aplikacji masz ustawionych wiele smaków produktów, skonfiguruj moduł :macrobenchmark tak, aby wiedział, jaki smak produktu Twojej aplikacji powinien utworzyć i porównać.

Przykłady na tej stronie wykorzystują 2 rodzaje produktów w module :app: demo i production, jak widać w tym fragmencie:

Kotlin

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

Odlotowy

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

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

Bez tej konfiguracji może wystąpić błąd kompilacji podobny do tego w przypadku wielu modułów 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:
           ...

W dwóch poniższych sekcjach opisano sposoby konfigurowania testu porównawczego z wieloma rodzajami produktów.

Użyj brakującej strategii wymiaru

Określenie missingDimensionStrategy w module defaultConfig w module :macrobenchmark informuje system kompilacji, że ma się przełączyć na wymiar smak. Określ, których wymiarów nie ma w module. W tym przykładzie jako wymiar domyślny używany jest rodzaj production:

Kotlin

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

Odlotowy

defaultConfig {
    missingDimensionStrategy "environment", "production"
}

Dzięki temu moduł :macrobenchmark może tworzyć i przeprowadzać testy porównawcze tylko o określonym smaku produktu. Jest to przydatne, gdy wiesz, że tylko jeden rodzaj produktu ma odpowiednią konfigurację do analizy porównawczej.

Definiowanie smaków produktów w module :macrobenchmark

Jeśli chcesz tworzyć różne smaki produktów i je porównywać, zdefiniuj je w module :macrobenchmark. Określ ją podobnie jak w module :app, ale przypisz productFlavors tylko do elementu dimension. Żadne inne ustawienia nie są wymagane:

Kotlin

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

Odlotowy

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

    production {
        dimension 'environment'
    }
}

Po zdefiniowaniu i zsynchronizowaniu projektu wybierz w panelu Warianty kompilacji odpowiedni wariant kompilacji, jak widać na ilustracji 4:

Wersje porównawcze dla projektu z rodzajami produktów, w których wybrano testy porównawcze i wersję

Rysunek 4. Warianty testów porównawczych dla projektu z rodzajami produktów, które mają wybrane wartości „productionBenchmark” i „release”.

Więcej informacji znajdziesz w artykule Naprawianie błędów kompilacji związanych z dopasowaniem wariantu.

Tworzenie klasy analizy porównawczej

Testy porównawcze są przeprowadzane za pomocą interfejsu MacrobenchmarkRule interfejsu API reguły JUnit4 w bibliotece Macrobenchmark. Zawiera metodę measureRepeated, która pozwala określić różne warunki uruchomienia i porównania aplikacji docelowej.

Musisz określić przynajmniej: packageName aplikacji docelowej, zakres danych metrics, które chcesz zmierzyć, i liczbę iterations, którą musi przeprowadzić test porównawczy.

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

Informacje o wszystkich opcjach dostosowywania testów porównawczych znajdziesz w sekcji Dostosowywanie testów porównawczych.

Przeprowadź test porównawczy

Uruchom test w Android Studio, by zmierzyć skuteczność aplikacji na urządzeniu. Testy porównawcze możesz przeprowadzać w taki sam sposób jak dowolne inne @Test z użyciem działania rynku znajdującego się obok klasy lub metody testowej, jak pokazano na rys. 5.

Uruchom makroporównanie z działaniem rynku obok klasy testowej

Rysunek 5. Uruchom Macroporównanie z działaniem rynku obok klasy testowej.

Wszystkie testy porównawcze w module Gradle możesz też uruchamiać z poziomu wiersza poleceń, wykonując polecenie connectedCheck:

./gradlew :macrobenchmark:connectedCheck

Aby uruchomić pojedynczy test, wykonaj te czynności:

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

Informacje o tym, jak uruchamiać i monitorować testy porównawcze w trybie ciągłej integracji, znajdziesz w sekcji Analiza porównawcza w ciągłej integracji.

Wyniki testu porównawczego

Po udanym przeprowadzeniu analizy porównawczej dane są wyświetlane bezpośrednio w Android Studio i wyjściowe na potrzeby użycia CI w pliku JSON. Każda zmierzona iteracja rejestruje osobny ślad systemu. Wyniki śledzenia możesz otworzyć, klikając linki w panelu Wyniki testu, jak pokazano na rys. 6:

Makroporównawcze wyniki startowe

Rysunek 6. Wyniki uruchamiania trybu Macroporównanie.

Po wczytaniu logu czasu Android Studio poprosi o wybranie procesu do analizy. Ten wybór jest wstępnie wypełniany przez docelowy proces aplikacji, jak widać na rys. 7:

Wybór procesu śledzenia w Studio

Rysunek 7. Wybór procesu śledzenia w Studio.

Po wczytaniu pliku śledzenia Studio wyniki pojawią się w narzędziu do profilowania procesora:

Ślad
studyjny

Rysunek 8. Śledzenie Studio.

Raporty JSON i wszystkie ślady profilowania są również automatycznie kopiowane z urządzenia do hosta. Są one zapisywane na hoście w tej lokalizacji:

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

Ręczne uzyskiwanie dostępu do plików śledzenia

Jeśli chcesz przeanalizować plik śledzenia za pomocą narzędzia Perfetto, musisz wykonać dodatkowe czynności. Perfetto umożliwia zbadanie wszystkich procesów realizowanych na urządzeniu podczas śledzenia, a profilowanie procesora w Android Studio ogranicza inspekcję do 1 procesu.

Jeśli wywołujesz testy w Android Studio lub z wiersza poleceń Gradle, pliki śledzenia są automatycznie kopiowane z urządzenia do hosta. Są one zapisywane na hoście w tej lokalizacji:

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

Gdy masz plik śledzenia w systemie hosta, możesz go otworzyć w Android Studio, klikając Plik > Otwórz w menu. Wyświetli się widok narzędzia do profilowania z poprzedniej sekcji.

Błędy konfiguracji

Jeśli aplikacja jest nieprawidłowo skonfigurowana (można ją debugować lub nie profilować), Macrobenchmark zwraca błąd, zamiast zgłaszać nieprawidłowy lub niepełny pomiar. Możesz pominąć te błędy za pomocą argumentu androidx.benchmark.suppressErrors.

Macroporównanie zwraca też błędy, gdy próbujesz zmierzyć emulator lub urządzenie o niskiej baterii, co może obniżyć dostępność rdzeni i szybkość zegara.

Dostosuj testy porównawcze

Funkcja measureRepeated akceptuje różne parametry, które wpływają na dane zbierane przez bibliotekę, sposób uruchamiania i kompilowania aplikacji oraz na liczbę iteracji testów porównawczych.

Rejestruj dane

Dane to główny typ informacji wyodrębnionych z testów porównawczych. Dostępne są te wskaźniki:

Więcej informacji o danych znajdziesz w artykule Rejestrowanie danych analizy porównawczej.

Popraw dane z logów czasu za pomocą zdarzeń niestandardowych

Przydatne może być instrumentowanie aplikacji za pomocą niestandardowych zdarzeń logu czasu, które są widoczne w pozostałej części raportu śledzenia i pomagają wskazywać problemy charakterystyczne dla Twojej aplikacji. Więcej informacji o tworzeniu niestandardowych zdarzeń logu czasu znajdziesz w sekcji Definiowanie zdarzeń niestandardowych.

Tryb kompilacji

Analiza porównawcza makr może określać element CompilationMode, który określa, jaka część aplikacji musi być wstępnie skompilowana z kodu bajtowego DEX (formatu kodu bajtowego w pliku APK) na kod maszyny (podobnie do wstępnie skompilowanego C++).

Domyślnie testy porównawcze makr są przeprowadzane w usłudze CompilationMode.DEFAULT, która instaluje profil podstawowy (jeśli jest dostępny) na Androidzie 7 (poziom interfejsu API 24) i nowszych. Jeśli używasz Androida 6 (poziom interfejsu API 23) lub starszego, tryb kompilacji w pełni kompiluje plik APK jako domyślne działanie systemowe.

Możesz zainstalować profil podstawowy, jeśli aplikacja docelowa zawiera zarówno profil podstawowy, jak i bibliotekę ProfileInstaller.

W Androidzie 7 i nowszych możesz dostosować CompilationMode tak, aby wpływało na liczbę wstępnej kompilacji na urządzeniu i symulujące różne poziomy kompilacji z wyprzedzeniem lub buforowania JIT. Zobacz CompilationMode.Full, CompilationMode.Partial, CompilationMode.None i CompilationMode.Ignore.

Ta funkcja opiera się na poleceniach kompilacji ART. Każdy test porównawczy usuwa dane profilowe przed rozpoczęciem, co pozwala uniknąć zakłóceń między testami porównawczymi.

Tryb uruchamiania

Aby rozpocząć aktywność, możesz przekazać wstępnie zdefiniowany tryb uruchamiania: COLD, WARM lub HOT. Ten parametr zmienia sposób uruchamiania działania i stan procesu na początku testu.

Więcej informacji o typach uruchamiania znajdziesz w artykule Czas uruchomienia aplikacji.

Próbki

Przykładowy projekt jest dostępny w MacrobenchmarkSample w repozytorium na GitHubie.

Prześlij opinię

Aby zgłosić problemy lub przesłać prośbę o dodanie funkcji do Jetpack Macrobenchmark, skorzystaj z publicznego narzędzia do śledzenia problemów.