Привет, Хабр! Часто при тестировании идет сравнение производительности двух версий, например, master ветки и feature ветки. Допустим, идет сравнение по бенчмаркам, т.е. сравнивается время выполнения запросов для некоторого количества кейсов. Понятно, что если, например, в feature ветке есть улучшение производительности (и ветка создавалась как раз для улучшения производительности), это улучшение на целевых кейсах можно проверить даже вручную. Однако, осталось проверить, нет ли ухудшения производительности в остальных кейсах. Относительно точное вычисление производительности в смысле среднего времени выполнения запроса в конкретном кейсе требует нескольких прогонов кейса и может занять некоторое время, поэтому полная проверка всех кейсов (с десятками прогонов каждого кейса для получения более точного среднего результата) может занять, например, дни.
Однако, часто требуется лишь проверить лишь наличие деградации в feature ветке по сравнению с master, а не знать относительно точное время выполнения каждого запроса в feature ветке, это зачастую актуально для PR. Например, в feature ветке в одном кейсе два запроса выполняются за 300 и 300 секунд, а в master ветке для этого кейса за 12, 11, 10 секунд, нужно ли проводить несколько запусков кейса в feature ветке, или и так понятно, что есть деградация? Методы математической статистики позволяет формально ответить на этот вопрос с заданной вероятностью, например, 0.95, чтобы можно было принять решение формально, а не интуитивно. Интересующимся статистическими методами проверки отсутствия деградации — добро пожаловать под кат :)
Математическая статистика предоставляет целый набор критериев для решения этой задачи, одним из подходящих можно считать критерий Кохрена-Кокса. В этой статье рассматривается этот простой и более общий критерий и случай только одного фактора и не рассматривается многофакторный дисперсионный анализ ANOVA, который может учесть, например, зависимость бенчмарков от условно ресурсов CPU, RAM и т.д.
Таким образом, для проверки гипотезы о том, что среднее одной выборки меньше среднего другой выборки (т.е. среднее время выполнения одного бенчмарка в одной версии меньше среднего времени выполнения этого бенчмарка в другой версии), используется критерий Кохрена-Кокса и односторонний тест.
Алгоритм применения критерия Кохрена-Кокса
Формулирование гипотез
Будем считать, что сравнивается производительность одного кейса для выборки (время выполнения кейса на master ветке) и выборки
(время выполнения того же кейса на feature ветке с возможными улучшениями).
Нулевая гипотеза
(среднее первой выборки не меньше среднего второй выборки), т.е. на master работает дольше и нет деградации.
Альтернативная гипотеза
(среднее первой выборки меньше среднего второй выборки), т.е. на master работало быстрее и есть деградация в feature ветке.
Алгоритм применения критерия Кохрена-Кокса
Даны две независимые выборки:
(размер
)
(размер
)
Вычисляем выборочные средние:
Вычисляем исправленные выборочные дисперсии (в знаменателе размер выборки минус 1):
Находим
-статистику Кохрена-Кокса:
Определяем число степеней свободы по формуле Уэлча, причем округляем
до ближайшего целого числа:
Определяем критическое значение
из таблицы распределения Стьюдента для одностороннего теста с уровнем значимости
.
Принимаем или отвергаем
:
Если
, отвергаем
в пользу
, т.е. среднее первой выборки значимо меньше среднего второй выборки.
Если
, нет оснований отвергать
, т.е. разница между средними не является статистически значимой.
Таким образом, критерий Кохрена-Кокса позволяет проверить гипотезу о том, что одно среднее меньше другого, даже если выборки разного размера и имеют разные дисперсии. Это делает его более гибким, чем стандартный -критерий Стьюдента.
Пример деградации в feature ветке
Проведем сравнение для двух выборок, первая выборка (т.е. результаты master ветки) содержит результаты выполнения в секундах для одного кейса: 12, 11, 10 секунд. Вторая выборка
(т.е. результаты feature ветки) содержит два значения времени выполнения запроса для того же кейса: 300 и 300 секунд.
Проведем тест Кохрена-Кокса для проверки гипотезы:
где первая выборка ,
и вторая выборка
,
.
Результаты вычислений:
-статистика:
Число степеней свободы:
Критическое значение:
Поскольку меньше критического значения
, мы отвергаем нулевую гипотезу. Это означает, что среднее первой выборки значимо меньше среднего второй выборки, значит, уже есть деградация в feature ветке по сравнению с master и дальнейшие прогоны этого кейса и исследование feature ветки для этого кейса не требуется.
Как видно, можно сравнить две выборки с разными размерами, что, например, позволяет не запускать кейс с 300 секундами в третий раз на feature ветке и сэкономить условно 5 минут.
Пример улучшения в feature ветке
Проведем сравнение одного кейса для результатов выполнения одного кейса в master: 12, 11, 14, 11, 12 секунд и результатов выполнения того же кейса в feature: 5, 6, 8, 12, 8 секунд.
У нас теперь две выборки одинакового размера, каждая содержит по 5 значений, первая выборка: , вторая выборка:
, размеры выборок
.
Найдем выборочные средние и выборочные дисперсии, рассчитаем -статистику:
Рассчитаем число степеней свободы по формуле Уэлча:
Критическое значение для уровня значимости и одностороннего теста равно .
Т.к. и мы проверяем гипотезу
против
,
то нулевая гипотеза не отвергается, т.е. среднее не меньше, чем среднее
, более того — оно значительно больше.
Зачем все это нужно? Теперь видно, что если в feature ветке в одном кейсе результат двух измерений производительности равен условно 300 и 300 секунд, а в master ветке 12, 11, 10 секунд, то с вероятностью 0.95 (и даже больше на самом деле) можно утверждать, что в этом кейсе в feature ветке есть деградация, и дальнейшие длительные выполнения запросов для этого кейса не требуются, что экономит время, причем такой вывод можно сделать формально и с заданной вероятностью, а не интуитивно.
Также, как было продемонстрировано, и для менее очевидного кейса для 12, 11, 14, 11, 12 секунд в master ветке и для 5, 6, 8, 12, 8 в feature нет деградации в feature ветке.
Таким образом, критерий Кохрена-Кокса позволяет сравнивать производительность одного кейса для двух версий (в частности, веток) динамически, выполнять по одному прогону кейса для каждой ветки и принимать решение, не требуя точного расчета среднего времени выполнения для каждого кейса каждой ветки на основе, например, 100 прогонов.
Описанный подход в общем случае не заменяет бенчмарки, но позволяет решить частную задачу сравнения производительности двух веток значительно быстрее, в некоторых случаях на порядки быстрее, что, например, актуально для анализа PR.
Успехов в тестировании и бенчмарках :)