Напишите микротест

Чтобы узнать, как использовать библиотеку Microbenchmark, внося изменения в код приложения, см. раздел «Быстрый старт» . Чтобы узнать, как выполнить полную настройку с более сложными изменениями в кодовой базе, см. раздел «Полная настройка проекта» .

Быстрый старт

В этом разделе показано, как протестировать бенчмаркинг и провести разовые измерения без необходимости переноса кода в модули. Для получения точных результатов производительности эти шаги подразумевают отключение отладки в вашем приложении, поэтому сохраните его в локальной рабочей копии, не внося изменения в систему управления версиями.

Для проведения разового сравнительного анализа выполните следующие действия:

  1. Добавьте библиотеку в файл build.gradle или build.gradle.kts вашего модуля:

    Котлин

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

    Круто

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

    Используйте зависимость implementation вместо зависимости androidTestImplementation . При использовании androidTestImplementation тесты производительности не запускаются, поскольку манифест библиотеки не объединён с манифестом приложения.

  2. Обновите тип debug сборки, чтобы он не был отлаживаемым:

    Котлин

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

    Круто

    android {
        ...
        buildTypes {
            debug {
                debuggable false
            }
        }
    }
  3. Измените testInstrumentationRunner на AndroidBenchmarkRunner :

    Котлин

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

    Круто

    android {
        ...
        defaultConfig {
            testInstrumentationRunner "androidx.benchmark.junit4.AndroidBenchmarkRunner"
        }
    }
  4. Добавьте экземпляр BenchmarkRule в тестовый файл в каталоге androidTest , чтобы добавить свой бенчмарк. Подробнее о написании бенчмарков см. в разделе Создание класса Microbenchmark .

    В следующем фрагменте кода показано, как добавить бенчмарк в инструментированный тест:

    Котлин

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

    Ява

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

Чтобы узнать, как написать бенчмарк, перейдите к разделу Создание класса Microbenchmark .

Полная настройка проекта

Чтобы настроить регулярный, а не разовый бенчмаркинг, изолируйте бенчмарки в отдельный модуль. Это поможет гарантировать, что их конфигурация, например, установка debuggable в значение false , будет отделена от обычных тестов.

Поскольку Microbenchmark запускает ваш код напрямую, поместите код, который вы хотите протестировать, в отдельный модуль Gradle и установите зависимость от этого модуля, как показано на рисунке 1.

структура приложения
Рисунок 1. Структура приложения с модулями Gradle :app , :microbenchmark и :benchmarkable , которая позволяет Microbenchmarks тестировать код в модуле :benchmarkable .

Чтобы добавить новый модуль Gradle, воспользуйтесь мастером модулей в Android Studio. Мастер создаст модуль, предварительно настроенный для бенчмаркинга, с добавленным каталогом бенчмарка и debuggable установленным в значение false .

  1. Щелкните правой кнопкой мыши свой проект или модуль на панели «Проект» в Android Studio и выберите «Создать» > «Модуль» .

  2. Выберите Benchmark на панели «Шаблоны» .

  3. Выберите Microbenchmark в качестве типа модуля бенчмарка.

  4. Введите «microbenchmark» в качестве имени модуля.

  5. Нажмите кнопку Готово .

Настроить новый библиотечный модуль
Рисунок 2. Добавление нового модуля Gradle в Android Studio Bumblebee.

После создания модуля измените его файл build.gradle или build.gradle.kts и добавьте androidTestImplementation в модуль, содержащий код для тестирования:

Котлин

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

Круто

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

Создать класс Microbenchmark

Бенчмарки — это стандартные инструментальные тесты. Для создания бенчмарка используйте класс BenchmarkRule , предоставляемый библиотекой. Для бенчмарка действий используйте ActivityScenario или ActivityScenarioRule . Для бенчмарка кода пользовательского интерфейса используйте @UiThreadTest .

Следующий код демонстрирует пример бенчмарка:

Котлин

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

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

Ява

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

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

Отключить время для настройки

Вы можете отключить замер времени для фрагментов кода, которые не хотите измерять, с помощью блока runWithTimingDisabled{} . Эти фрагменты обычно представляют собой код, который необходимо запускать на каждой итерации теста.

Котлин

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

Ява

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

Постарайтесь минимизировать объём работы внутри блока measureRepeated и блока runWithTimingDisabled . Блок measureRepeated выполняется несколько раз, что может повлиять на общее время выполнения бенчмарка. Если вам нужно проверить некоторые результаты бенчмарка, вы можете подтвердить последний результат, а не делать это при каждой итерации.

Запустить тест

В Android Studio запустите тест производительности, как и любой другой @Test используя действие gutter рядом с вашим тестовым классом или методом, как показано на рисунке 3.

Запустить Microbenchmark
Рисунок 3. Запуск теста Microbenchmark с использованием действия «полка» рядом с тестовым классом.

В качестве альтернативы, из командной строки запустите connectedCheck , чтобы запустить все тесты из указанного модуля Gradle:

./gradlew benchmark:connectedCheck

Или один тест:

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

Результаты контрольных тестов

После успешного запуска Microbenchmark метрики отображаются непосредственно в Android Studio, а полный отчет о тестировании с дополнительными метриками и информацией об устройстве доступен в формате JSON.

Результаты микробенчмарка
Рисунок 4. Результаты микробенчмарка.

Отчёты JSON и любые данные профилирования также автоматически копируются с устройства на хост. Они записываются на хост-компьютере в следующем месте:

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

По умолчанию отчет JSON записывается на диск устройства во внешнюю общую папку мультимедиа тестового APK, которая обычно находится в /storage/emulated/0/Android/media/**app_id**/**app_id**-benchmarkData.json .

Ошибки конфигурации

Библиотека определяет следующие условия, чтобы гарантировать, что ваш проект и среда настроены на производительность, соответствующую выпуску:

  • Debuggable имеет значение false .
  • Используется физическое устройство — эмуляторы не поддерживаются.
  • Часы блокируются, если устройство имеет права root.
  • Достаточный уровень заряда батареи устройства — не менее 25%.

Если какая-либо из предыдущих проверок не пройдена, тест выдает сообщение об ошибке, чтобы исключить неточные измерения.

Чтобы подавить определенные типы ошибок как предупреждения и не допустить остановки теста производительности из-за них, передайте тип ошибки в списке, разделенном запятыми, в аргумент инструментария androidx.benchmark.suppressErrors .

Вы можете установить это из скрипта Gradle, как показано в следующем примере:

Котлин

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

Круто

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

Вы также можете подавлять ошибки из командной строки:

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

Подавление ошибок позволяет тесту запускаться в неправильно настроенном состоянии, а выходные данные теста намеренно переименовываются путём добавления к именам тестов имени ошибки. Например, запуск отлаживаемого теста с подавлением ошибок, описанным в предыдущем фрагменте, добавляет к именам тестов префикс DEBUGGABLE_ .

{% дословно %} {% endverbatim %} {% дословно %} {% endverbatim %}