Utwórz mikroporównanie

Aby dowiedzieć się, jak korzystać z biblioteki Microbenchmark, wprowadzając zmiany w kodzie aplikacji, zapoznaj się z sekcją Krótkie wprowadzenie. Aby dowiedzieć się, jak przeprowadzić pełną konfigurację z bardziej skomplikowanymi zmianami w kodzie, przeczytaj sekcję Pełna konfiguracja projektu.

Krótkie wprowadzenie

Z tej sekcji dowiesz się, jak przeprowadzić test porównawczy i jednorazowe pomiary bez konieczności przenoszenia kodu do modułów. Aby uzyskać dokładne wyniki dotyczące wydajności, wykonaj te czynności, które obejmują wyłączenie debugowania w aplikacji. Dlatego zachowaj lokalną kopię roboczą bez zatwierdzania zmian w systemie kontroli wersji.

Aby przeprowadzić jednorazową analizę porównawczą:

  1. Dodaj bibliotekę do pliku build.gradle lub build.gradle.kts modułu:

    Kotlin

    dependencies {
        implementation("androidx.benchmark:benchmark-junit4:1.2.4")
    }
    

    Odlotowe

    dependencies {
        implementation 'androidx.benchmark:benchmark-junit4:1.2.4'
    }
    

    Użyj zależności implementation zamiast androidTestImplementation zależności. Jeśli korzystasz z metody androidTestImplementation, testy porównawcze nie będą jest uruchamiane, ponieważ biblioteka manifest nie jest zintegrowana z aplikacją. pliku manifestu.

  2. Zmień typ kompilacji debug, aby nie można było go debugować:

    Kotlin

    android {
        ...
        buildTypes {
            debug {
                isDebuggable = false
            }
        }
    }
    

    Groovy

    android {
        ...
        buildTypes {
            debug {
                debuggable false
            }
        }
    }
    
  3. Zmień testInstrumentationRunner na AndroidBenchmarkRunner:

    Kotlin

    android {
        ...
        defaultConfig {
            testInstrumentationRunner = "androidx.benchmark.junit4.AndroidBenchmarkRunner"
        }
    }
    

    Groovy

    android {
        ...
        defaultConfig {
            testInstrumentationRunner "androidx.benchmark.junit4.AndroidBenchmarkRunner"
        }
    }
    
  4. Dodaj wystąpienie BenchmarkRule w pliku testowym w pliku androidTest, aby dodać test porównawczy. Więcej informacji o tworzeniu testów porównawczych znajdziesz w artykule Tworzenie klasy testów mikroporównawczych.

    Ten fragment kodu pokazuje, jak dodać punkt odniesienia do testu z użyciem pomiarów:

    Kotlin

    @RunWith(AndroidJUnit4::class)
    class SampleBenchmark {
        @get:Rule
        val benchmarkRule = BenchmarkRule()
    
        @Test
        fun benchmarkSomeWork() {
            benchmarkRule.measureRepeated {
                doSomeWork()
            }
        }
    }
    

    Java

    @RunWith(AndroidJUnit4.class)
    class SampleBenchmark {
        @Rule
        public BenchmarkRule benchmarkRule = new BenchmarkRule();
    
        @Test
        public void benchmarkSomeWork() {
                BenchmarkRuleKt.measureRepeated(
                    (Function1<BenchmarkRule.Scope, Unit>) scope -> doSomeWork()
                );
           }
        }
    }
    

Aby dowiedzieć się, jak napisać test porównawczy, przejdź do sekcji Tworzenie klasy testów mikroporównawczych.

Pełna konfiguracja projektu

Aby skonfigurować regularne testy porównawcze, a nie jednorazowe, analizy porównawcze w osobnym module. Dzięki temu ich konfiguracja, np. ustawienie debuggable na false, jest oddzielona od zwykłych testów.

Test porównawczy uruchamia Twój kod bezpośrednio, więc umieść kod, który chcesz testów porównawczych w osobnym module Gradle i ustaw zależność od tego modułu jako co pokazano na ilustracji 1.

struktura aplikacji
Rysunek 1. Struktura aplikacji z modułami Gradle :app, :microbenchmark:benchmarkable, która umożliwia testowanie kodu w modułach :benchmarkable w Microbenchmarks.

Aby dodać nowy moduł Gradle, możesz użyć kreatora modułów w Android Studio. tworzy moduł skonfigurowany wstępnie do testów porównawczych, dodano katalog testu porównawczego i ustawienie debuggable na false.

  1. W panelu Projekt w Android Studio kliknij prawym przyciskiem myszy projekt lub moduł, a potem wybierz Nowy > Moduł.

  2. W panelu Szablony wybierz Analiza porównawcza.

  3. Jako typ modułu testu porównawczego wybierz Microbenchmark.

  4. Wpisz „microbenchmark” dla nazwy modułu.

  5. Kliknij Zakończ.

Konfigurowanie nowego modułu biblioteki
Rysunek 2. Dodawanie nowego modułu Gradle w Android Studio Trzmiel

Po utworzeniu modułu zmień jego plik build.gradle lub build.gradle.kts i dodaj do modułu zawierającego kod do testów porównawczych element androidTestImplementation:

Kotlin

dependencies {
    // The module name might be different.
    androidTestImplementation(project(":benchmarkable"))
}

Groovy

dependencies {
    // The module name might be different.
    androidTestImplementation project(':benchmarkable')
}

Tworzenie zajęć z mikrobenchmarkami

Wskaźniki to standardowe testy z wykorzystaniem instrumentacji. Aby utworzyć punkt odniesienia, użyj klasy BenchmarkRule udostępnionej przez bibliotekę. Aby porównać aktywności, użyj funkcji ActivityScenario lub ActivityScenarioRule. Aby porównać kod interfejsu, użyj @UiThreadTest.

Poniższy kod pokazuje przykładowe testy porównawcze:

Kotlin

@RunWith(AndroidJUnit4::class)
class SampleBenchmark {
    @get:Rule
    val benchmarkRule = BenchmarkRule()

    @Test
    fun benchmarkSomeWork() {
        benchmarkRule.measureRepeated {
            doSomeWork()
        }
    }
}
    

Java

@RunWith(AndroidJUnit4.class)
class SampleBenchmark {
    @Rule
    public BenchmarkRule benchmarkRule = new BenchmarkRule();

    @Test
    public void benchmarkSomeWork() {
        final BenchmarkState state = benchmarkRule.getState();
        while (state.keepRunning()) {
            doSomeWork();
        }
    }
}
    

Wyłącz czas konfiguracji

Możesz wyłączyć czas w sekcjach kodu, których nie chcesz mierzyć za pomocą funkcji Blokuj runWithTimingDisabled{}. Te sekcje zwykle reprezentują kod, który musisz uruchomić w przypadku każdej iteracji testu porównawczego.

Kotlin

// using random with the same seed, so that it generates the same data every run
private val random = Random(0)

// create the array once and just copy it in benchmarks
private val unsorted = IntArray(10_000) { random.nextInt() }

@Test
fun benchmark_quickSort() {
    // ...
    benchmarkRule.measureRepeated {
        // copy the array with timing disabled to measure only the algorithm itself
        listToSort = runWithTimingDisabled { unsorted.copyOf() }

        // sort the array in place and measure how long it takes
        SortingAlgorithms.quickSort(listToSort)
    }

    // assert only once not to add overhead to the benchmarks
    assertTrue(listToSort.isSorted)
}
    

Java

private final int[] unsorted = new int[10000];

public SampleBenchmark() {
    // Use random with the same seed, so that it generates the same data every
    // run.
    Random random = new Random(0);

    // Create the array once and copy it in benchmarks.
    Arrays.setAll(unsorted, (index) -> random.nextInt());
}

@Test
public void benchmark_quickSort() {
    final BenchmarkState state = benchmarkRule.getState();

    int[] listToSort = new int[0];

    while (state.keepRunning()) {
        
        // Copy the array with timing disabled to measure only the algorithm
        // itself.
        state.pauseTiming();
        listToSort = Arrays.copyOf(unsorted, 10000);
        state.resumeTiming();
        
        // Sort the array in place and measure how long it takes.
        SortingAlgorithms.quickSort(listToSort);
    }

    // Assert only once, not to add overhead to the benchmarks.
    assertTrue(SortingAlgorithmsKt.isSorted(listToSort));
}
    

Postaraj się zminimalizować ilość pracy wykonywanej wewnątrz bloku measureRepeated i w środku runWithTimingDisabled. Blok measureRepeated jest wykonywany wielokrotnie i może wpływać na łączny czas potrzebny do przeprowadzenia testu porównawczego. Jeśli Musisz zweryfikować jakieś wyniki testu porównawczego, możesz wskazać ostatni wynik zamiast przy każdej wersji testu porównawczego.

Przeprowadzanie testu porównawczego

W Android Studio przeprowadź test porównawczy tak samo jak w przypadku dowolnego @Test, używając działania rynien obok klasy lub metody testowej, jak to widać na rysunku 3.

Uruchamianie mikrotestu porównawczego
Rysunek 3. Uruchom test Microbenchmark za pomocą działania w pasku bocznym obok klasy testowej.

Możesz też z poziomu wiersza poleceń uruchomić connectedCheck, aby uruchomić wszystkie polecenia testów z określonego modułu Gradle:

./gradlew benchmark:connectedCheck

Lub pojedynczy test:

./gradlew benchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.benchmark.SampleBenchmark#benchmarkSomeWork

Wyniki testu porównawczego

Po pomyślnym uruchomieniu mikrotestu dane są wyświetlane bezpośrednio w Android Studio, a pełny raport testów porównawczych z dodatkowymi danymi i informacjami o urządzeniu jest dostępny w formacie JSON.

Wyniki mikroanalizy
Rysunek 4. wyniki mikroanalizy
.

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

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

Domyślnie raport w formacie JSON jest zapisywany na dysku urządzenia w zewnętrznym folderze udostępnionych multimediów pliku APK testowego, który zwykle znajduje się w folderze /storage/emulated/0/Android/media/**app_id**/**app_id**-benchmarkData.json.

Błędy konfiguracji

Biblioteka wykrywa te warunki, aby zapewnić, że projekt i środowisko są skonfigurowane pod kątem dokładnej wydajności w wersji:

  • Pole „Możliwość debugowania” ma wartość false.
  • Używane jest urządzenie fizyczne – emulatory nie są obsługiwane.
  • Jeśli urządzenie jest zrootowane, zegary są zablokowane.
  • Urządzenie musi mieć co najmniej 25% poziom naładowania baterii.

Jeśli któraś z wcześniejszych kontroli zakończy się niepowodzeniem, test porównawczy zgłosi błąd, aby zniechęcaj do niedokładnych pomiarów.

Aby ukryć określone typy błędów jako ostrzeżenia i uniemożliwić im zatrzymanie testu porównawczego, przekaż typ błędu do instrumentacji w postaci listy rozdzielanej przecinkami argument androidx.benchmark.suppressErrors.

Możesz to ustawić w skrypcie Gradle, jak pokazano w tym przykładzie:

Kotlin

android {
    defaultConfig {
       …
      testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE,LOW-BATTERY"
    }
}

Odlotowe

android {
    defaultConfig {
       …
      testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE,LOW-BATTERY"
    }
}

Możesz też pominąć błędy przy użyciu wiersza poleceń:

$ ./gradlew :benchmark:connectedCheck -P andoidtestInstrumentationRunnerArguments.androidx.benchmark.supperssErrors=DEBUGGABLE,LOW-BATTERY

Pomijanie błędów umożliwia uruchomienie testu w nieprawidłowo skonfigurowanym stanie, a wynik testu jest celowo przemianowany przez dodanie do nazwy testu błędu. Na przykład uruchomienie testu porównawczego z możliwością debugowania z wyłączeniem w poprzednim fragmencie kodu powoduje, że nazwy testów mają przedrostek DEBUGGABLE_.