Biblioteki Macrobenchmark używaj do testowania większych przypadków użycia aplikacji,
w tym uruchamiania aplikacji i złożonych manipulacji interfejsem, takich jak przewijanie
LazyColumn czy uruchamianie animacji. Jeśli chcesz przetestować mniejsze obszary
kodu, zapoznaj się z artykułem Microbenchmark. Z tej strony dowiesz się, jak skonfigurować bibliotekę Macrobenchmark.
Biblioteka wyświetla wyniki testów porównawczych w konsoli Android Studio oraz w pliku JSON zawierającym więcej szczegółów. Udostępnia też pliki śledzenia, które możesz wczytać i przeanalizować w Android Studio.
Biblioteki Macrobenchmark używaj w środowisku ciągłej integracji (CI), zgodnie z opisem w artykule Testowanie w trybie ciągłej integracji.
Za pomocą biblioteki Macrobenchmark możesz generować profile podstawowe. Najpierw skonfiguruj bibliotekę Macrobenchmark, a potem możesz utworzyć profil podstawowy.
Biblioteka Macrobenchmark to zalecane narzędzie do testowania interfejsów utworzonych za pomocą Jetpack Compose. Aby dowiedzieć się, jak pisać testy UI Automator, które wchodzą w interakcję z węzłami Compose, przeczytaj artykuł Współdziałanie.
Konfigurowanie projektu
Zalecamy używanie biblioteki Macrobenchmark z najnowszą wersją Android Studio.
Konfigurowanie modułu Macrobenchmark
Testy porównawcze Macrobenchmark wymagają modułu com.android.test – oddzielnego od kodu aplikacji
– który odpowiada za uruchamianie testów mierzących aplikację.
W Android Studio dostępny jest szablon, który upraszcza konfigurowanie modułu Macrobenchmark. Szablon modułu testów porównawczych automatycznie tworzy w projekcie moduł do pomiaru aplikacji utworzonej przez moduł aplikacji, w tym przykładowy test porównawczy uruchamiania.
Aby utworzyć nowy moduł za pomocą szablonu modułu:
W panelu Projekt w Android Studio kliknij prawym przyciskiem myszy projekt lub moduł i wybierz Nowy > Moduł.
W panelu Szablony wybierz Test porównawczy. Możesz dostosować aplikację docelową – czyli aplikację, która ma zostać przetestowana – oraz nazwę pakietu i modułu nowego modułu Macrobenchmark.
Kliknij Zakończ.
Konfigurowanie aplikacji
Aby przetestować aplikację – zwaną celem testu porównawczego Macrobenchmark – musi ona być
profileable, co umożliwia odczytywanie szczegółowych informacji o śledzeniu bez
wpływu na wydajność. Kreator modułu automatycznie dodaje tag <profileable>
do pliku AndroidManifest.xml aplikacji.
Upewnij się, że aplikacja docelowa zawiera ProfilerInstaller w wersji 1.3 lub nowszej,
która jest potrzebna bibliotece Macrobenchmark do włączania przechwytywania i resetowania profilu oraz
czyszczenia pamięci podręcznej shaderów.
Skonfiguruj testowaną aplikację tak, aby była jak najbardziej zbliżona do wersji produkcyjnej. Ustaw ją jako niepodlegającą debugowaniu i najlepiej z włączoną minimalizacją, co poprawia wydajność. Zwykle robisz to, tworząc kopię wariantu wersji, która działa tak samo, ale jest podpisywana lokalnie za pomocą kluczy debugowania.
Możesz też użyć initWith, aby poinstruować Gradle, aby zrobił to 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") } }
Dynamiczny
buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "keep-rules.pro" ) // In real app, this would use its own release keystore signingConfig = signingConfigs.getByName("debug") baselineProfile.automaticGenerationDuringBuild = true } }
Aby mieć pewność, że uruchomienie testu porównawczego spowoduje skompilowanie i przetestowanie prawidłowego wariantu aplikacji, jak pokazano na rysunku 2, wykonaj te czynności:
- Przeprowadź synchronizację Gradle.
- Otwórz panel Warianty kompilacji.
- Wybierz wariant testu porównawczego zarówno aplikacji, jak i modułu Macrobenchmark.
(Opcjonalnie) Konfigurowanie aplikacji wielomodułowej
Jeśli Twoja aplikacja ma więcej niż 1 moduł Gradle, upewnij się, że skrypty kompilacji wiedzą, który wariant kompilacji ma zostać 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 wcześniej.
Kotlin
create("benchmark") { initWith(getByName("release")) signingConfig = signingConfigs.getByName("debug") matchingFallbacks += listOf("release") }
Dynamiczny
benchmark { initWith buildTypes.release signingConfig signingConfigs.debug matchingFallbacks = ['release'] }
Bez tego nowo dodany typ kompilacji benchmark spowoduje niepowodzenie kompilacji i wyświetlenie tego komunikatu o błędzie:
> Could not resolve project :shared.
Required by:
project :app
> No matching variant of project :shared was found.
...
Podczas wybierania wariantów kompilacji w projekcie wybierz benchmark dla modułów
:app i :macrobenchmark oraz release dla wszystkich innych modułów w aplikacji
, jak pokazano na rysunku 3:
Więcej informacji znajdziesz w artykule Rozwiązywanie błędów kompilacji związanych z dopasowywaniem wariantów.
(Opcjonalnie) Konfigurowanie wariantów produktu
Jeśli w aplikacji masz skonfigurowanych kilka wariantów produktu, skonfiguruj moduł :macrobenchmark tak, aby wiedział, który wariant produktu ma zostać skompilowany i przetestowany.
Przykłady na tej stronie używają 2 wariantów produktu w module :app: demo i production, jak pokazano w tym fragmencie kodu:
Kotlin
flavorDimensions += "environment" productFlavors { create("demo") { dimension = "environment" // ... } create("production") { dimension = "environment" // ... } }
Dynamiczny
flavorDimensions 'environment' productFlavors { demo { dimension 'environment' // ... } production { dimension 'environment' // ... } }
Bez tej konfiguracji może wystąpić błąd kompilacji podobny do błędu spowodowanego przez wiele 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 2 kolejnych sekcjach opisujemy, jak skonfigurować testy porównawcze z kilkoma wariantami produktu.
Używanie missingDimensionStrategy
Określenie missingDimensionStrategy w defaultConfig modułu :macrobenchmark informuje system kompilacji, aby powrócił do wymiaru wariantu. Określ, których wymiarów używać, jeśli nie znajdziesz ich w module.
W tym przykładzie wariant production jest używany jako domyślny wymiar:
Kotlin
defaultConfig { missingDimensionStrategy("environment", "production") }
Dynamiczny
defaultConfig { missingDimensionStrategy "environment", "production" }
W ten sposób moduł :macrobenchmark może tylko kompilować i testować określony wariant produktu, co jest przydatne, jeśli wiesz, że tylko 1 wariant produktu ma odpowiednią konfigurację do testowania.
Definiowanie wariantów produktu w module :macrobenchmark
Jeśli chcesz kompilować i testować inne warianty produktu, zdefiniuj je w module :macrobenchmark. Określ je podobnie jak w module :app, ale przypisz productFlavors tylko do dimension. Nie są wymagane żadne inne ustawienia:
Kotlin
flavorDimensions += "environment" productFlavors { create("demo") { dimension = "environment" } create("production") { dimension = "environment" } }
Dynamiczny
flavorDimensions 'environment' productFlavors { demo { dimension 'environment' } production { dimension 'environment' } }
Po zdefiniowaniu i zsynchronizowaniu projektu wybierz odpowiedni wariant kompilacji w panelu Warianty kompilacji , jak pokazano na rysunku 4:
Więcej informacji znajdziesz w artykule Rozwiązywanie błędów kompilacji związanych z dopasowywaniem wariantów.
Tworzenie klasy Macrobenchmark
Testy porównawcze są przeprowadzane za pomocą MacrobenchmarkRule reguły JUnit4
interfejsu API w bibliotece Macrobenchmark. Zawiera on metodę measureRepeated
która umożliwia określenie różnych warunków uruchamiania i testowania aplikacji docelowej.
Musisz co najmniej określić packageName aplikacji docelowej, metrics, które chcesz zmierzyć, oraz liczbę iterations, które mają zostać wykonane w teście porównawczym.
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, ) { // starts default launch activity uiAutomator { startApp(TARGET_PACKAGE) } } }
Wszystkie opcje dostosowywania testu porównawczego znajdziesz w sekcji Dostosowywanie testów porównawczych.
Testowanie interakcji z interfejsem Compose
W poprzednim przykładzie mierzyliśmy uruchamianie aplikacji, ale często trzeba też mierzyć wydajność interfejsu, np. liczbę pominiętych klatek (jank) podczas przewijania.
Aby przetestować aplikację Jetpack Compose, np. zmierzyć FrameTimingMetric podczas przewijania LazyColumn, możesz użyć UI Automator do bezpośredniej interakcji z węzłami Compose, jak pokazano w tym fragmencie kodu.
@LargeTest
@RunWith(AndroidJUnit4::class)
class ComposeScrollBenchmark {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
@Test
fun scrollLazyColumn() = benchmarkRule.measureRepeated(
packageName = "com.example.compose.app",
metrics = listOf(FrameTimingMetric()),
iterations = 5,
startupMode = StartupMode.WARM,
setupBlock = { pressHome() }
) {
startActivityAndWait()
// Find the Compose node using the testTag defined in your app
val lazyColumn = device.findObject(By.res("my_lazy_column"))
// Simulate a scroll gesture to measure FrameTimingMetric
lazyColumn.setGestureMargin(device.displayWidth / 5)
lazyColumn.fling(Direction.DOWN)
}
}
Uruchamianie testu porównawczego
Uruchom test w Android Studio, aby zmierzyć wydajność aplikacji na urządzeniu. Testy porównawcze możesz uruchamiać tak samo jak inne testy @Test, używając działania w rynnie obok klasy lub metody testowej, jak pokazano na rysunku 5.
Możesz też uruchomić wszystkie testy porównawcze w module Gradle z wiersza poleceń, wykonując polecenie connectedCheck:
./gradlew :macrobenchmark:connectedCheckAby uruchomić pojedynczy test, wykonaj te czynności:
./gradlew :macrobenchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.macrobenchmark.startup.SampleStartupBenchmark#startupInformacje o tym, jak uruchamiać testy porównawcze w trybie ciągłej integracji i je monitorować, znajdziesz w artykule Testowanie w trybie ciągłej integracji.
Wyniki testu porównawczego
Po pomyślnym uruchomieniu testu porównawczego dane są wyświetlane bezpośrednio w Android Studio i zapisywane w pliku JSON do użycia w trybie ciągłej integracji. Każda zmierzona iteracja rejestruje oddzielne śledzenie systemu. Wyniki śledzenia możesz otworzyć, klikając linki w panelu Wyniki testu , jak pokazano na rysunku 6:
Po wczytaniu śledzenia Android Studio wyświetli prośbę o wybranie procesu do analizy. Wybór jest wstępnie wypełniony procesem aplikacji docelowej, jak pokazano na rysunku 7:
Po wczytaniu pliku śledzenia Studio wyświetli wyniki w narzędziu do profilowania procesora:
Raporty JSON i wszystkie ślady profilowania są też automatycznie kopiowane z urządzenia na 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ęczny dostęp do plików śledzenia
Jeśli chcesz przeanalizować plik śledzenia za pomocą narzędzia Perfetto, musisz wykonać dodatkowe czynności. Perfetto umożliwia sprawdzenie wszystkich procesów zachodzących na urządzeniu podczas śledzenia, a narzędzie do profilowania procesora w Android Studio ogranicza sprawdzanie do jednego procesu.
Jeśli wywołasz testy z Android Studio lub z wiersza poleceń Gradle, pliki śledzenia zostaną automatycznie skopiowane z urządzenia na 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, wybierając w menu Plik > Otwórz. Spowoduje to wyświetlenie widoku narzędzia do profilowania pokazanego w poprzedniej sekcji.
Błędy konfiguracji
Jeśli aplikacja jest nieprawidłowo skonfigurowana – można ją debugować lub nie można jej profilować – Macrobenchmark zwraca błąd zamiast nieprawidłowego lub niepełnego pomiaru. Te błędy możesz
pominąć za pomocą androidx.benchmark.suppressErrors
argumentu.
Macrobenchmark zwraca też błędy podczas próby pomiaru na emulatorze lub na urządzeniu z niskim poziomem naładowania baterii, co może wpłynąć na dostępność rdzeni i szybkość zegara.
Dostosowywanie testów porównawczych
Funkcja measureRepeated akceptuje różne parametry, które wpływają na to,
jakie dane zbiera biblioteka, jak aplikacja jest uruchamiana i kompilowana oraz ile
iteracji ma zostać wykonanych w teście porównawczym.
Przechwytywanie danych
Dane to główny typ informacji wyodrębnianych z testów porównawczych. Dostępne są te dane:
Więcej informacji o danych znajdziesz w artykule Przechwytywanie danych Macrobenchmark.
Ulepszanie danych śledzenia za pomocą zdarzeń niestandardowych
Może się przydać instrumentowanie aplikacji za pomocą niestandardowych zdarzeń śledzenia, które są widoczne w pozostałej części raportu śledzenia i mogą pomóc w wskazaniu problemów specyficznych dla Twojej aplikacji. Więcej informacji o tworzeniu niestandardowych zdarzeń śledzenia znajdziesz w artykule Definiowanie zdarzeń niestandardowych.
CompilationMode
Testy porównawcze Macrobenchmark mogą określać CompilationMode, który definiuje, ile
aplikacji musi zostać wstępnie skompilowane z kodu bajtowego DEX (format kodu bajtowego w
APK) do kodu maszynowego (podobnie jak wstępnie skompilowany kod C++).
Domyślnie testy porównawcze Macrobenchmark są uruchamiane w trybie CompilationMode.DEFAULT, który
instaluje profil podstawowy – jeśli jest dostępny – na Androidzie 7 (poziom API 24) i nowszym.
Jeśli używasz Androida 6 (poziom API 23) lub starszego, tryb kompilacji w pełni kompiluje APK jako domyślne działanie systemu.
Możesz zainstalować profil podstawowy, jeśli aplikacja docelowa zawiera zarówno profil podstawowy
, jak i bibliotekę ProfileInstaller.
Na Androidzie 7 i nowszym możesz dostosować CompilationMode, aby wpływać na ilość wstępnej kompilacji na urządzeniu i naśladować różne poziomy kompilacji AOT lub buforowania JIT. Zobacz CompilationMode.Full,
CompilationMode.Partial, CompilationMode.None i
CompilationMode.Ignore.
Ta funkcja jest oparta na poleceniach kompilacji ART. Każdy test porównawczy przed rozpoczęciem czyści dane profilu, aby zapobiec zakłóceniom między testami.
StartupMode
Aby uruchomić działanie, 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 uruchamiania aplikacji.
Przykłady
Przykładowy projekt jest dostępny w repozytorium GitHub w sekcji Macrobenchmark Sample.
Przesyłanie opinii
Aby zgłosić problemy lub przesłać prośby o dodanie funkcji do Jetpack Macrobenchmark, skorzystaj z publicznego narzędzia do śledzenia problemów.
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy język JavaScript jest wyłączony.
- Przechwytywanie danych Macrobenchmark
- Tworzenie profili podstawowych {:#creating-profile-rules}
- Automatyzowanie pomiarów za pomocą biblioteki Macrobenchmark {:#measuring-optimization}