Тестирование производительности

Android 8.0 включает в себя тесты производительности Binder и hwbinder для проверки пропускной способности и задержки. Хотя существует множество сценариев для обнаружения заметных проблем с производительностью, выполнение таких сценариев может занять много времени, а результаты часто недоступны до тех пор, пока система не будет интегрирована. Использование предоставленных тестов производительности упрощает тестирование во время разработки, раньше выявляет серьезные проблемы и улучшает взаимодействие с пользователем.

Тесты производительности включают следующие четыре категории:

  • пропускная способность связующего (доступна в system/libhwbinder/vts/performance/Benchmark_binder.cpp )
  • задержка связывателя (доступна в frameworks/native/libs/binder/tests/schd-dbg.cpp )
  • пропускная способность hwbinder (доступна в system/libhwbinder/vts/performance/Benchmark.cpp )
  • задержка hwbinder (доступна в system/libhwbinder/vts/performance/Latency.cpp )

О связующем и hwbinder

Binder и hwbinder — это инфраструктуры межпроцессного взаимодействия (IPC) Android, которые используют один и тот же драйвер Linux, но имеют следующие качественные различия:

Аспект связующее Хвбиндер
Цель Предоставьте схему IPC общего назначения для платформы. Взаимодействие с оборудованием
Свойство Оптимизирован для использования платформы Android. Минимальные накладные расходы, низкая задержка
Изменение политики планирования для переднего/фонового плана Да Нет
Прохождение аргументов Использует сериализацию, поддерживаемую объектом Parcel. Использует буферы разброса и позволяет избежать накладных расходов на копирование данных, необходимых для сериализации посылок.
Приоритетное наследование Нет Да

Связующее и гидросвязующее процессы

Визуализатор systrace отображает транзакции следующим образом:

Рисунок 1. Визуализация процессов связывания в Systrace.

В приведенном выше примере:

  • Четыре (4) процесса schd-dbg являются клиентскими процессами.
  • Четыре (4) процесса связывания являются серверными процессами (имя начинается с Binder и заканчивается порядковым номером).
  • Клиентский процесс всегда связан с серверным процессом, который посвящен своему клиенту.
  • Все пары процессов клиент-сервер планируются ядром одновременно и независимо друг от друга.

В ЦП 1 ядро ​​ОС выполняет клиент для выдачи запроса. Затем он использует тот же процессор, когда это возможно, для пробуждения серверного процесса, обработки запроса и обратного переключения контекста после завершения запроса.

Пропускная способность и задержка

В идеальной транзакции, когда процессы клиента и сервера переключаются плавно, тесты пропускной способности и задержки не выдают существенно отличающихся сообщений. Однако, когда ядро ​​ОС обрабатывает запрос на прерывание (IRQ) от оборудования, ожидает блокировки или просто решает не обрабатывать сообщение немедленно, может образоваться пузырь задержки.

Рисунок 2. Пузырь задержки из-за различий в пропускной способности и задержке.

Тест пропускной способности генерирует большое количество транзакций с различными размерами полезной нагрузки, обеспечивая хорошую оценку обычного времени транзакции (в лучшем случае) и максимальной пропускной способности, которую может достичь связующее устройство.

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

Обработка инверсий приоритетов

Инверсия приоритета происходит, когда поток с более высоким приоритетом логически ожидает потока с более низким приоритетом. Приложения реального времени (RT) имеют проблему инверсии приоритетов:

Рисунок 3. Инверсия приоритетов в приложениях реального времени.

При использовании планирования Linux Completely Fair Scheduler (CFS) поток всегда имеет возможность запуститься, даже если другие потоки имеют более высокий приоритет. В результате приложения с планированием CFS обрабатывают инверсию приоритетов как ожидаемое поведение, а не как проблему. Однако в тех случаях, когда платформе Android требуется планирование RT, чтобы гарантировать привилегии потоков с высоким приоритетом, необходимо разрешить инверсию приоритетов.

Пример инверсии приоритета во время транзакции связывания (поток RT логически блокируется другими потоками CFS во время ожидания обслуживания потока связывания):

Рисунок 4. Инверсия приоритетов, заблокированные потоки реального времени.

Чтобы избежать блокировок, вы можете использовать наследование приоритетов для временного повышения уровня потока Binder до потока RT, когда он обслуживает запрос от клиента RT. Имейте в виду, что планирование RT имеет ограниченные ресурсы, и его следует использовать осторожно. В системе с n процессорами максимальное количество текущих потоков RT также равно n ; дополнительным потокам RT, возможно, придется подождать (и, следовательно, пропустить сроки), если все процессоры заняты другими потоками RT.

Чтобы разрешить все возможные инверсии приоритетов, вы можете использовать наследование приоритетов как для связывателя, так и для hwbinder. Однако, поскольку связыватель широко используется в системе, включение наследования приоритетов для транзакций связующего может привести к спаму в системе большего количества потоков RT, чем она может обслужить.

Запуск тестов пропускной способности

Тест пропускной способности выполняется с учетом пропускной способности транзакций Binder/hwbinder. В системе, которая не перегружена, пузырьки задержки редки, и их влияние можно устранить, если количество итераций достаточно велико.

  • Тест пропускной способности связующего находится в system/libhwbinder/vts/performance/Benchmark_binder.cpp .
  • Тест производительности hwbinder находится в system/libhwbinder/vts/performance/Benchmark.cpp .

Результаты испытаний

Пример результатов теста пропускной способности для транзакций, использующих разные размеры полезной нагрузки:

Benchmark                      Time          CPU           Iterations
---------------------------------------------------------------------
BM_sendVec_binderize/4         70302 ns      32820 ns      21054
BM_sendVec_binderize/8         69974 ns      32700 ns      21296
BM_sendVec_binderize/16        70079 ns      32750 ns      21365
BM_sendVec_binderize/32        69907 ns      32686 ns      21310
BM_sendVec_binderize/64        70338 ns      32810 ns      21398
BM_sendVec_binderize/128       70012 ns      32768 ns      21377
BM_sendVec_binderize/256       69836 ns      32740 ns      21329
BM_sendVec_binderize/512       69986 ns      32830 ns      21296
BM_sendVec_binderize/1024      69714 ns      32757 ns      21319
BM_sendVec_binderize/2k        75002 ns      34520 ns      20305
BM_sendVec_binderize/4k        81955 ns      39116 ns      17895
BM_sendVec_binderize/8k        95316 ns      45710 ns      15350
BM_sendVec_binderize/16k      112751 ns      54417 ns      12679
BM_sendVec_binderize/32k      146642 ns      71339 ns       9901
BM_sendVec_binderize/64k      214796 ns     104665 ns       6495
  • Время указывает задержку туда и обратно, измеренную в реальном времени.
  • ЦП указывает суммарное время, в течение которого ЦП запланированы для теста.
  • Итерации указывают, сколько раз выполнялась тестовая функция.

Например, для 8-байтовой полезной нагрузки:

BM_sendVec_binderize/8         69974 ns      32700 ns      21296

… максимальная производительность, которую может достичь связующее, рассчитывается как:

МАКС. пропускная способность с 8-байтовой полезной нагрузкой = (8 * 21296)/69974 ~= 2,423 бит/нс ~= 2,268 Гбит/с

Варианты тестирования

Чтобы получить результаты в формате .json, запустите тест с аргументом --benchmark_format=json :

libhwbinder_benchmark --benchmark_format=json
{
  "context": {
    "date": "2017-05-17 08:32:47",
    "num_cpus": 4,
    "mhz_per_cpu": 19,
    "cpu_scaling_enabled": true,
    "library_build_type": "release"
  },
  "benchmarks": [
    {
      "name": "BM_sendVec_binderize/4",
      "iterations": 32342,
      "real_time": 47809,
      "cpu_time": 21906,
      "time_unit": "ns"
    },
   ….
}

Запустите тесты задержки

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

  • Тест задержки связывателя находится в frameworks/native/libs/binder/tests/schd-dbg.cpp .
  • Тест задержки hwbinder находится в system/libhwbinder/vts/performance/Latency.cpp .

Результаты испытаний

Результаты (в формате .json) показывают статистику средней/лучшей/худшей задержки и количества пропущенных сроков.

Варианты тестирования

Тесты задержки принимают следующие параметры:

Команда Описание
-i value Укажите количество итераций.
-pair value Укажите количество пар процессов.
-deadline_us 2500 Сроки уточняйте у нас.
-v Получите подробный (отладочный) вывод.
-trace Остановите отслеживание при достижении крайнего срока.

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

Укажите итерации

Пример с большим количеством итераций и отключенным подробным выводом:

libhwbinder_latency -i 5000 -pair 3
{
"cfg":{"pair":3,"iterations":5000,"deadline_us":2500},
"P0":{"SYNC":"GOOD","S":9352,"I":10000,"R":0.9352,
  "other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996},
  "fifo_ms": { "avg":0.16, "wst":1.5 , "bst":0.067, "miss":0, "meetR":1}
},
"P1":{"SYNC":"GOOD","S":9334,"I":10000,"R":0.9334,
  "other_ms":{ "avg":0.19, "wst":2.9 , "bst":0.055, "miss":2, "meetR":0.9996},
  "fifo_ms": { "avg":0.16, "wst":3.1 , "bst":0.066, "miss":1, "meetR":0.9998}
},
"P2":{"SYNC":"GOOD","S":9369,"I":10000,"R":0.9369,
  "other_ms":{ "avg":0.19, "wst":4.8 , "bst":0.055, "miss":6, "meetR":0.9988},
  "fifo_ms": { "avg":0.15, "wst":1.8 , "bst":0.067, "miss":0, "meetR":1}
},
"inheritance": "PASS"
}

Результаты этих испытаний показывают следующее:

"pair":3
Создает одну пару клиент-сервер.
"iterations": 5000
Включает 5000 итераций.
"deadline_us":2500
Срок — 2500 мкс (2,5 мс); ожидается, что большинство транзакций будут соответствовать этому значению.
"I": 10000
Одна итерация тестирования включает две (2) транзакции:
  • Одна транзакция с обычным приоритетом ( CFS other )
  • Одна транзакция с приоритетом реального времени ( RT-fifo )
5000 итераций равны 10000 транзакций.
"S": 9352
9352 транзакции синхронизируются на одном процессоре.
"R": 0.9352
Указывает соотношение, при котором клиент и сервер синхронизируются на одном процессоре.
"other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996}
Средний ( avg ), худший ( wst ) и лучший ( bst ) случай для всех транзакций, выполненных вызывающей стороной с обычным приоритетом. Две транзакции miss в срок, в результате чего коэффициент выполнения ( meetR ) составляет 0,9996.
"fifo_ms": { "avg":0.16, "wst":1.5 , "bst":0.067, "miss":0, "meetR":1}
other_ms , но для транзакций, выпущенных клиентом с приоритетом rt_fifo . Вполне вероятно (но не обязательно), что fifo_ms имеет лучший результат, other_ms , с более низкими значениями avg и wst и более высоким значением meetR (разница может быть еще более существенной при нагрузке в фоновом режиме).

Примечание. Фоновая нагрузка может повлиять на результат пропускной способности и other_ms в тесте задержки. Только fifo_ms может показывать аналогичные результаты, пока фоновая загрузка имеет более низкий приоритет, чем RT-fifo .

Укажите значения пары

Каждый клиентский процесс связан с серверным процессом, предназначенным для клиента, и каждая пара может быть запланирована независимо для любого ЦП. Однако миграция ЦП не должна происходить во время транзакции, пока флаг SYNC установлен в honor .

Убедитесь, что система не перегружена! Несмотря на то, что в перегруженной системе ожидается высокая задержка, результаты тестирования перегруженной системы не предоставляют полезной информации. Чтобы протестировать систему с более высоким давлением, используйте -pair #cpu-1 (или -pair #cpu с осторожностью). Тестирование с использованием -pair n с n > #cpu перегружает систему и генерирует бесполезную информацию.

Укажите значения срока

После обширного тестирования пользовательских сценариев (выполнение теста задержки на сертифицированном продукте) мы определили, что крайним сроком для соблюдения является 2,5 мс. Для новых приложений с более высокими требованиями (например, 1000 фотографий в секунду) значение этого срока изменится.

Укажите подробный вывод

Использование опции -v отображает подробный вывод. Пример:

libhwbinder_latency -i 1 -v

-------------------------------------------------- service pid: 8674 tid: 8674 cpu: 1 SCHED_OTHER 0
-------------------------------------------------- main pid: 8673 tid: 8673 cpu: 1 -------------------------------------------------- client pid: 8677 tid: 8677 cpu: 0 SCHED_OTHER 0
-------------------------------------------------- fifo-caller pid: 8677 tid: 8678 cpu: 0 SCHED_FIFO 99 -------------------------------------------------- hwbinder pid: 8674 tid: 8676 cpu: 0 ??? 99
-------------------------------------------------- other-caller pid: 8677 tid: 8677 cpu: 0 SCHED_OTHER 0 -------------------------------------------------- hwbinder pid: 8674 tid: 8676 cpu: 0 SCHED_OTHER 0
  • Поток службы создается с приоритетом SCHED_OTHER и выполняется на CPU:1 с pid 8674 .
  • Затем первая транзакция запускается fifo-caller . Для обслуживания этой транзакции hwbinder повышает приоритет сервера ( pid: 8674 tid: 8676 ) до 99, а также помечает его временным классом планирования (напечатано как ??? ). Затем планировщик помещает серверный процесс в CPU:0 для запуска и синхронизирует его с тем же процессором, что и его клиент.
  • Второй вызывающий объект транзакции имеет приоритет SCHED_OTHER . Сервер понижает свою версию и обслуживает вызывающую сторону с приоритетом SCHED_OTHER .

Используйте трассировку для отладки

Вы можете указать опцию -trace для устранения проблем с задержкой. При использовании тест задержки останавливает запись журнала трассировки в момент обнаружения плохой задержки. Пример:

atrace --async_start -b 8000 -c sched idle workq binder_driver sync freq
libhwbinder_latency -deadline_us 50000 -trace -i 50000 -pair 3
deadline triggered: halt ∓ stop trace
log:/sys/kernel/debug/tracing/trace

Следующие компоненты могут влиять на задержку:

  • Режим сборки Android . Режим Eng обычно медленнее, чем режим пользовательской отладки.
  • Рамки . Как служба платформы использует ioctl для настройки связующего?
  • Связующий водитель . Поддерживает ли драйвер детальную блокировку? Содержит ли он все исправления, повышающие производительность?
  • Версия ядра . Чем лучше возможности реального времени имеет ядро, тем лучше результаты.
  • Конфигурация ядра . Содержит ли конфигурация ядра конфигурации DEBUG , такие как DEBUG_PREEMPT и DEBUG_SPIN_LOCK ?
  • Планировщик ядра . Есть ли в ядре планировщик Energy-Aware (EAS) или Heterogeneous Multi-Processing (HMP)? Влияют ли какие-либо драйверы ядра (драйвер cpu-freq , драйвер cpu-idle , cpu-hotplug и т. д.) на планировщик?