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

Чтобы узнать, как использовать библиотеку 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. Выберите «Бенчмарк» на панели «Шаблоны» .

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

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

  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 используя действие поля рядом с вашим тестовым классом или методом, как показано на рисунке 3.

Запустите микробенчмарк
Рисунок 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 .

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

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

  • Для параметра Debugable установлено значение false .
  • Используется физическое устройство — эмуляторы не поддерживаются.
  • Часы блокируются, если устройство рутировано.
  • Достаточный уровень заряда батареи на устройстве не менее 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_ .

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