Тест продуктивності: дивно і просто

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

Короткий зміст статті:


Передісторія
Одного разу, подорожуючи в поїзді, я захотів порахувати, яка відстань між стовпами електропередач. Озброївшись звичайними годинами і оцінюючи середню швидкість поїзда 80-100км/год (25 м/с), я засікав час між 2-ма стовпами. Як не дивно, цей наївний метод давав дуже гнітючі результат, аж до 1.5-2 кратної різниці. Природно метод нескладно було виправити, що я і зробив, досить було засікти 1 хвилину і порахувати кількість стовпів. І не важливо, що миттєва швидкість впродовж хвилини може змінюватись і навіть не важливо порахуємо ми останній стовп або хвилина мине посередині, бо як вимірювань цілком достатньо для необхідного результату.
Зміст тесту в тому, щоб отримати переконливі для себе і для інших вимірювання.

Тести «на коліні»
Ця історія мені нагадує те, що відбувається з тестуванням продуктивності в Software Engineering. Досить часте явище — запуск 1-2 тестів, побудова графіків та отримання висновків про scalability система. Навіть, якщо є можливість застосувати МНК або дізнатися стандартну помилку, це не робиться за непотрібністю.» Особливо цікава ситуація, коли після цих 2 вимірювань, люди обговорюють наскільки швидка система, як вона масштабується і порівнюють її з іншими системами за особистим відчуттям.
Звичайно, оцінити, наскільки швидко виконується команда, не складно. З іншого боку, швидше не означає краще. Системи мають понад 10 різноманітних параметрів, від hardware на якому вони працюють до input, які вводить користувач у різні моменти часу. І найчастіше 2 еквівалентних алгоритми можуть давати різні параметри масштабованості в різних умовах, що робить вибір зовсім не очевидним.

Недовіру до тестів
З іншого боку результати вимірювань завжди залишаються джерелом спекуляцій і недовір.
— Вчора ми міряли було X, а сьогодні 1.1*X. Хтось щось міняв? — 10% — це нормально, у нас тепер більше записів в БД.
— При проведенні тесту був відключений антивірус, скайп, анімація заставки?
— Не-не, для нормальних тестів нам треба закупити кластер серверів, встановити микросекундную синхронізацію часу між ними… видалити ОС, запускати в захищеному режимі…
— Скільки користувачів ми підтримуємо? У нас 5000 зареєстрованих користувачів, раптом 20% з них залягання, треба запускати тести з 1000 паралельними агентами.


Що ж нам робити?
По-перше, варто визнати, що залізо, яке ми маємо, у нас вже є і треба отримати максимум результатів саме на ньому. Інше питання, як ми зможемо пояснити поведінку на інших машинах (production/quality testing). Ті, хто ратує за експерименти «чистої кімнати», просто вам не довіряють, так як ви не даєте досить пояснень або даних, «чиста кімната» — це ілюзія.
По-друге, найголовніше перевага у тестуванні програм — це дешевизна тестів. Якби фізики могли провести 100 тестів спрощеної ситуації замість 5 повноцінних, вони б точно вибрали 100 (і для перевірки результатів 5 повноцінних :) ). Ні в якому разі не можна втрачати дешевизни тестів, запускайте їх у себе, у колезі, на сервері, вранці і в обід. Не піддавайтеся спокусі «реальних» часових тестів з тисячами користувачів, важливіше розуміти, як поводиться система, ніж знати кілька абсолютних чисел.
По-третє, зберігайте результати. Цінність тестів представляють самі вимірювання, а не висновки. Висновки набагато частіше бувають неправильними, ніж самі вимірювання.

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


Найпростіший тест
Відразу обмовимося, що ми розглядаємо систему як «чорний ящик». Так як системи можуть працювати під віртуальні машиною, з використанням БД і без, не має сенсу розчленовувати систему і брати вимірювання в середині (зазвичай це призводить до неврахованим важливим моментам). Зате якщо є можливість тестувати систему, в різних конфігурація це обов'язково слід робити.

Для тестування навіть простого тесту, краще мати незалежну систему як JMeter, яка може підрахувати результати, усереднити. Звичайно, налаштування система вимагає час, а хочеться отримати результат набагато швидше і ми пишемо щось таке.

long t = - System.currentTimeMillis();
int count = 100;
while (count -- > 0) operation();
long time = (t + System.currentTimeMillis()) / 100;


Запис результату вимірювання
Запустивши один раз ми отримуємо число X. Запускаємо ще раз отримуємо 1.5*X 2 *X, 0.7*X. насправді тут можна і потрібно зупинитися, якщо ми робимо тимчасовий завмер і нам не треба вставляти це число у звіт. Якщо ж ми хочемо поділитися цим числом з ким-то, нам важливо, щоб воно відповідало іншими вимірами і не викликало підозр.
Першим «логічним» кроком здається покласти числа X і усереднити їх, але, насправді, усереднення середніх ні що інше, як збільшення count для одного тесту. Як не дивно збільшення count може призвести до ще більш стабільним результатам, особливо якщо ви будете запускати тест і робити щось одночасно.

Мінімальний час виконання як краща статистика
Проблема в тому, що середня є не стабільною характеристикою, одного заваленого тіста, выполнявшегося в 10 разів довше, буде достатньо, щоб ваші результати не збігалися з іншими. Як не парадоксально для простих performance тестів бажано брати мінімальний час виконання . Природно operation() повинна бути вимірювана в даному контектсе, зазвичай 100 мс — 500 мс для системи більш, ніж достатньо. Звичайно, мінімальний час не буде 1 до 1 співпадати із спостережуваним ефектом або з реальним, але це число буде порівнянно з іншими вимірами.

Квантили
Квантили 10%, 50% (медіана), 90% є більш стабільними, ніж середнє, і набагато інформативніше. Ми можемо дізнатися з якою ймовірністю запит буде виконуватися час 0.5*X або 0.7*X. З ними є інша проблема, порахувати квантили на коліні набагато складніше ніж взяти min, max.
JMeter надає вимірювання медіани і 90% в Aggregate Report з коробки, що слід користуватися.


Параметризований тест
В результаті вимірювань ми отримуємо деяке число (медіану, мінімум чи інше), але що ми можемо сказати про нашу систему (функції) по одному числу? Уявіть ви автоматизуєте процес отримання цього числа, і кожен день ви будете перевіряти, коли вам треба бити на сполох і шукати винних? Приміром, ось типовий графік один і той же тест кожен день.

Прихований текстDaily test

Якщо ми захочемо написати звіт продуктивності, з одним числом він буде виглядати порожньо. Тому ми обов'язково протестуємо для різних параметрів. Тести для різних параметрів дадуть нам гарний графік і уявлення про scalability системи.

Тест з одним параметром
Розглянемо систему з одним числовим параметром. Насамперед необхідно вибрати значення параметрів. Не має сенсу вибирати з різних діапазонів, як [1, 100, 10000], ви просто проводите 3 абсолютно різних незв'язних тіста і знайти залежність на таких числах буде неможливо. Уявіть ви хочете побудувати графік, які числа ви б вибрали? Щось схоже на [X*1 X * 2 X*3, X*4,X*5, ].

Отже вибираємо 5-10 (7 найкраще) контрольних точок, для кожної точки проводимо 3-7 вимірювань, беремо мінімальну кількість для кожної точки і будуємо графік.
Scalability parameter day graph

Складність алгоритму
Як можна помітити точки розташовуються якраз навколо уявної прямої лінії. Тепер ми підходимо до самої цікавої частини вимірювань, ми можемо визначити складність алгоритму виходячи з вимірів. Визначення складності алгоритму на підставі тестів набагато простіше для складних програм, ніж аналіз тексту вихідних програм. За допомогою тесту можна навіть знайти спеціальні точки, коли складність змінюється, наприклад, запуск Full GC.

Визначення складності програми за результатами тесту є прямою задачею Регресійного аналізу. Очевидно, що не існує загального способу знаходження функції тільки за точка, тому для початку робиться припущення про деякій залежності, а потім вона перевіряється. В нашому випадку і в більшості інших, ми припускаємо що функцією є лінійна залежність.

Метод найменших квадратів (лінійна модель)
Для пошуку коефіцієнтів лінійної залежності є простий і оптимальний метод МНК. Перевага цього методу в тому, що формули можна запрограмувати 10 рядків і вони абсолютно зрозумілі.
y = a + bx 
a = ([xy] - b[x])/[x^2]
b = ([y] - a[x])/ n


Представимо наші обчислення в таблиці.
Table results

У виділена сходинці ми бачимо лінійний коефіцієнт нашої моделі, він дорівнює 95.54, вільний коефіцієнт 2688. Тепер ми можемо виконати простий, але не очевидний фокус, ми можемо надати значення цих чисел. 95.54 вимірюється в мілісекундах (як і наші вимірювання), 95.54 — час, який ми витрачаємо на кожну компоненту, а 2688 мс час, який ми витрачаємо на саму систему, не залежить від кількості компонент. Даний метод дозволив нам виділити досить точно час зовнішньої системи, в даному випадку БД, хоча воно в десятки разів перевищує час 1-ї компоненти. Якби ми користувалися формулою Time_with_N_component/N нам би довелося заміряти для N>1000, щоб похибка виявилася менше 10%.

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

На графіку результати незалежних запусків тесту в різний час, що підтверджує більшу стабільність лінійного коефіцієнта, ніж окремо взятих тестів.
Scalability parameter many days graph

Оцінка лінійності моделі і коефіцієнт Пірсона
Використовуючи графік ми можемо наочно побачити, що наші виміри дійсно задовольняють лінійної моделі, але цей метод далеко не точний і ми не можемо його автоматизувати. У цьому випадку нам може допомогти коефіцієнт Пірсона. Цей метод дійсно показує відхилення від прямої лінії, але для 5-10 вимірювань його явно недостатньо. Нижче наведено приклад, явно не лінійної залежності, але коефіцієнт Пірсона досить високий.

Повертаючись до нашої таблиці, знаючи ovehead системи (вільний коефіцієнт) ми можемо порахувати лінійний коефіцієнт для кожного виміру, що в таблиці і зроблено. Як ми бачимо числа (100, 101, 93, 96, 102, 81, 94, 100, 93, 98) — досить випадково розподілені близько 95, що і дає нам вагомі підстави вважати, що залежність лінійна. Слідуючи букві математики, насправді відхилення від середньої величини повинні відповідати нормальному розподілу, а для перевірки нормального розподілу достатньо перевірити критерій Колмогорова-Смирнова, але це ми залишимо для досвідчених тестувальників.

Як це не дивно, не всі залежності є лінійними. Перше, що приходить на розум, це квадратична залежність. Насправді квадратична залежність дуже небезпечна, вона вбиває performance спочатку повільно, а потім дуже швидко. Навіть якщо у вас 1000 елементів все виконується за частки секунди, то для 10000 це вже будуть десятки секунд (множиться на 100). Іншим прикладом, є сортування, яка не може бути вирішена за лінійний час. Порахуємо наскільки можна застосувати метод лінійної аналізу для алгоритмів з складність O(n*log n)

(10n log 10n )/ (n log n)= 10 + (10*log 10)/(log n)


Тобто для n >= 1000, відхилення в межах 10%, що істотно, але в деяких випадках може застосовуватися, особливо якщо коефіцієнт при log досить великий.

Розглянемо приклад нелінійної залежності.
Нелінійна складність алгоритмуTable results : not linear dependency

Перше, що слід відзначити, негативний overhead, з очевидних причин система не може мати від'ємне час витрачається на підготовку. Друге, дивлячись на колонку коефіцієнтів, можна помітити закономірність, лінійний коефіцієнт знижується, а потім зростає. Це нагадує графік параболи.

Тест з двома і більшим числом параметрів
Природно, що більшість систем не складаються з одного параметра. Приміром, програма читання з таблиці вже складається з 2-х параметрів, колонок і рядків. Використовуючи параметризрвані тести, ми можемо порахувати які витрати на читання рядків з 100 колонок (нехай 100мс) і які витрати на читання колонки для 100 рядків (нехай 150мс). 100*100мс != 100*150мс і це не парадокс, просто ми не враховуємо, що в швидкості читання рядків вже закладено overhead читання колонок 100. Тобто 100мс/100 колонок= 1мс — це не швидкість читання однієї клітинки! Насправді 2-х вимірів буде недостатньо для розрахунку швидкості читання однієї клітинки. Загальна формула така, де A — витрати на одну клітинку, B — на одну сходинку, C — на колонку:
Time(row, column) = A * row * column + B * row + C * column + Overhead
 


Складемо систему рівнянь, враховуючи наявні значення і ще одне необхідне вимірювання:
Time(row, 100) = 100 * A * row + B * row + o = 100 * row + o.
Time(row, 50) = 50 * A * row + B * row + o = 60 * row + o.
Time(100, column) = 100 * B * column + C * column + o = 150 * column + o.

100 * A + B = 100.
50 * A + B = 55.
100 * B + C = 150.


Звідси, отримуємо A = 0.9 мс, B = 10 мс, C = 50 мс.

Звичайно, маючи формулу на подобу ЛМНК для даного випадку, всі розрахунки би спростилися і автоматизувалися. У загальному випадку, до нас не застосуємо загальний ЛМНК, бо як функція, яка лінійна по кожному з аргументів, аж ніяк не багатовимірна лінійна функція (гіперплощина N-1 просторі). Можливо скористатися градієнтним методом знаходження коефіцієнтів, але це вже не буде аналітичний спосіб.


Багатокористувацькі тести і тести багатоядерних систем
Міф «throughput per core»
Одним з улюблених занять з performance тестами є екстраполяція. Особливо люди люблять екстраполювати в ту область, для яких вони не можуть отримати значень. Наприклад, маючи в системі 2 ядра або 1 ядро, хочеться проэкстраполировать як система вела себе з 10 ядрами. І звичайно ж перше невірне припущення у тому, що залежність лінійна. Для нормального визначення лінійної залежності необхідно від 5 точок, що звичайно ж неможливо отримати на 2х ядрах.

Закон Амдала
Одним з найбільш близьких наближень є закон Амдала.
Amdahl law
Він заснований на розрахунку відсотка паралеллизируемого коду α ( поза блоку синхронізації) і синхронизируемоего коду (1 — α). Якщо один процес займає час T на одному ядрі, тоді при множинних запущених завданнях N часом буде T' = T*α + (1-α)*N*T. В середньому звичайно ж N/2, але Amdahl допускає N. Паралельне прискорення відповідно S = N*T/T' = N / (α + (1-α)*N)=1 / (α/N + (1 — α)).

Звичайно ж, наведений вище графік, не настільки драматичним в реальності (адже там логарифмічна шкала по X). Однак істотним недоліком блоків синхронізації, є асимптота. Умовно кажучи, не можливо нарощуючи потужність подолати межу прискорення lim S= 1 / (1 — α). І ця межа досить жорсткий, тобто для 10% синхронізованого коду, межа 10, для 5% (що дуже добре) межа 20.

Функція має межу, але вона постійно зростає, з цього виникає, дивна, на перший погляд, завдання: оцінити яке hardware оптимально для нашого алгоритму. В реальності збільшити відсоток параллизированного буває досить складно. Повернемося до формули T' = T*α + (1-α)*N*T, оптимальним з точки зору ефективності: якщо ядро буде простоювати, стільки ж часу скільки і буде працювати. Тобто T*α=(1-α)*N*T, звідси отримуємо N =
α/(1-α). Для 10% — 9 ядер, для 5% — 19 ядер.

Зв'язок кількості користувачів та кількості ядер. Ідеальний графік.
Модель прискорення обчислень є теоретично можливою, але не завжди є реальною. Розглянемо ситуацію клієнт-сервер, коли N клієнтів постійно запускають деяку задачу на сервері, одного за одним, і ми не відчуваємо ніяких витрат на синхронізацію результатів, так як клієнти повністю не залежні! Ведення статистики наприклад вводить елемент синхронізації. Маючи M-ядерну машину, ми очікуємо, що середній час запиту T N < M однаково, а коли N > M час запиту зростає пропорційно кількості ядер і користувачів. Порахуємо throughput як кількість оброблюваних запитів в секунду і отримаємо такі «ідеальний» графік.

Ідеальні графікиIdea graph
Idea throughput graph


Експериментальні вимірювання
Природно ідеальні графіки досяжні, якщо ми маємо 0% synchronized блоків (критичних секцій). Нижче наведені реальні вимірювання одного алгоритму з різними значення параметра.
Core/throughput

Ми можемо розрахувати лінійний коефіцієнт і побудувати графік. Так само маючи машину з 8 ядрами, можна провести серію експериментів для 2, 4, 8 ядер. З результатів тестів можна зазначити, що система з 4 ядрами і 4 користувачами веде себе точно так само як система з 8 ядрами і 4 користувачам. Звичайно, це було очікувано, і дає нам можливість проводити тільки одну серію тестів для машини з максимальною кількістю ядер.
Експериментальні вимірювання, використовуючи лінійний коефіцієнтCore/parameter throughput


Графіки вимірювань близькі за значенням до закону Амдала, але все-таки істотно відрізняється. Маючи вимірювання для 1, 2, 4, 8 ядер, можна розрахувати кількість непараллезируемоего коду за формулою
Amdahl estimation

Де NP — кількість ядер, SU = Throughpt NP core / Throughput 1 core. Згідно із законом Амдала це число повинне бути постійним, але у всіх вимірах це число падає, хоча і не значно (91% — 85%).

Графік throughput per core не завжди являє собою безперервну лінію. Наприклад, при нестачі пам'яті або при роботі GC відхилення в throughput можуть бути дуже значними.
Значні коливання throughput при Full GCCore/throughput with Full GC



Поведінковий тест
Throughput
При вимірах навантаження багатокористувацьких систем ми ввели визначення Throughput = NumberOfConcurrentUsers / AverageTimeResponse. Для інтерпретації результатів Throughput — це пропускна здатність системи, яка кількість користувачів система може обслужити в момент часу, і це визначення тісно пов'язане з теорією масового обслуговування. Складність вимірювання throughput полягає в тому, що значення залежить від вхідного потоку. Наприклад, в системах масового обслуговування, передбачається, що час очікування відповіді не залежить від того, скільки заявок в черзі. У простій програмної реалізації, без черги заявок, час між всіма потоками буде ділитися і відповідно система буде деградувати. Важливо зауважити, що не варто довіряти JMeter вимірам throughput, було помічено, що Jmeter усереднює throughput між усіма кроками тесту, що є не правильним.

Розглянемо наступний випадок: при навантаженні з 1 користувачем, система видає Throughput = 10, при 2-х — Throughput=5. Така ситуація цілком можлива, так як типовий графік Throughput/User — ця функція яка має один локальний (і глобальний максимум).
Отже, при вхідному потоці 1 користувач кожні 125мс, система буде обробляти 8 користувачів в секунду (вхідний throughput).
При вхідному потоці 2 користувача кожні 125мс система почне коллапсировать, так як 8 (вхідний throughput) > 5 (можливого throughput).

Коллапсірующая система
Розглянемо приклад колапсуючої системи детальніше. Після проведення тесту Throughput/Users у нас є такі результати.
Throughput measurements

Users — кількість одночасних користувачів в системі, Progress per user — яку кількість роботи у відсотках користувач виконує за одну секунду. Подумки сэмулируем ситуацію, що кожну секунду приходить 10 користувачів і починають виконувати одну і ту ж операцію, питання, чи зможе система обслуговувати даний потік.
System progress

За 1 секунду 10 користувачів в середньому виконають тільки 20% своєї роботи, виходячи з припущення, що у середньому вони виконують все за 5. На 2-й секунді в системі вже буде 20 користувачів і вони будуть розділяти ресурси між 20 потоками, що ще зменшить відсоток виконуваної роботи. Продовжимо ряд до того, момент коли перші 10 користувачів закінчать роботу (теоретично вони її повинні закінчити так як ряд 1/2 + 1/3 + 1/4… розходиться).
Collapse evolution

Досить очевидно, що система сколлапсирует, так як за 80 секунд в системі буде 800 користувачів, а в цей момент зможуть закінчити тільки перші 10 користувачів.

Даний тест показує, що при будь-якому розподілі вхідного потоку, якщо вхідний throughput (математичне очікування) більше максимального
вимірюваного throughput для системи, система почне деградувати і при постійної навантаженні впаде. Але зворотне невірно, у 1-му прикладі максимальний вимірюваний throughput (=10) > вхідного (8), але система також не зможе впоратися.

Система в стаціонарному режимі
Цікавим випадком є працездатна система. Взявши за основу наші вимірювання, проведемо тест, що кожні 1 секунду приходять 2 нових користувача. Так як мінімальний час відповіді перевищує секунду, то спочатку кількість користувачів буде накопичуватися.
Stabilized system

Як ми бачимо система увійде в стаціонарний режим саме в тій точці, графіка коли вимірюваний throughput збігається з вхідною throughput. Кількість користувачів в системі в середньому буде 10.

З цього можна зробити висновок, що графік Throughput/Users з одного боку являє кількість оброблюваних користувачів в секунду (throughput) і кількість користувачів в системі (users). Падіння графіка праворуч від цієї точки характеризує тільки стабільність системи в стресових ситуаціях і залежність від характеру вхідного розподілу. У будь-якому випадку, проводячи тести Throughput/Users, буде зовсім не зайвим провести behavioral test з приблизними характеристиками.


Дивовижне розподіл
При проведенні тестів продуктивності практично завжди є вимірювання займають набагато більше часу, ніж очікувалося. Якщо час тестування досить велике, то можна спостерігати таку картину. Як з цих вимірів вибрати одне число?
Timeline results

Вибір статистики
Найпростішою статистикою є середнє, але з зазначених вище причин вона не зовсім стабільна, особливо для малого кількості вимірювань. Для визначення квантилів зручно скористатися графіком функції розподілу. Завдяки чудовому JMeter плагіну у нас є така можливість. Після перших 10-15 вимірювань зазвичай картина недостатньо ясна, тому для детального вивчення функції буде потрібно від 100 вимірювань.
Перші вимірюванняFirst measurements cum distribution

Final measurements cum distribution

Отримати N-квантиль з даного графіка дуже просто, достатньо взяти значення функції в даної точки. Функція показує досить дивно поведінка навколо мінімуму, але далі зростає цілком стабільно і тільки біля 95% квантиля починається різкий підйом.

Розподіл?
Є дане розподіл аналітичним або відомим? Для цього можна побудувати графік щільності розподілу і спробувати подивитися відомі функції, на щастя, їх не так много.
Final measurements distribution

Чесно кажучи цей метод не приніс ніяких результатів, на перший погляд схожі функції розподілу: Бета-розподіл, розподіл Максквелла, виявилися досить далекі від статистик.

Мінімум і експоненційний розподіл
Важливо відзначити, що область значень нашої випадкової величини аж ніяк не [0, +∞ [, а деякий [Min, +∞[. Ми не можемо очікувати, що програма може виконатися швидше, ніж теоретичний мінімум. Якщо припустити, що вимірюваний мінімум сходиться до теоретичного і відняти це число з усіх статистик, то можна наблютать досить цікаву закономірність.
Table results

Виявляється Minimum + StdDev = Mean (Average), причому це характерно для всіх вимірювань. Є один відомий розподіл у якого, математичні очікування збігається з дисперсією (variance), це експоненційний розподіл. Хоча графік щільності розподілу відрізняється на початку області визначення, основні квантили цілком збігаються. Цілком можливо випадкова величина є сумою експоненціального розподілу і нормального, що цілком пояснює коливання навколо точки теоретичного мінімуму.

Дисперсія і середнє
На жаль, мені не вдалося знайти теоретичного обґрунтування, чому результати тестів задовольняють експоненціальним розподілом. Найчастіше експоненційний розподіл фігурує в задачах часу відмови пристроїв і навіть часу життя людини. Неясно так само, чи є це специфікою платформи (Windows) або Java GC або якихось фізичних процесів, що відбуваються в комп'ютері.

Однак, враховуючи, що кожне експоненційний розподіл задається 2 параметрами (дисперсією та математичним очікуванням) і функція розподілу performance test експоненціальна, можна вважати, що для peformance тіста, нам необхідно і достатньо тільки 2 показників. Середня — час виконання тесту, дисперсія — відхилення від цього часу. Природно, чим менше дисперсія, тим краще, але однозначно сказати, що краще зменшити середню або дисперсію, не можна.

Якщо у когось є теорія, звідки береться дисперсія і як впливає той чи інший алгоритм на її значення, прошу поділитися. Від себе хочу зауважити, що залежності між часом виконання тесту та дисперсії, я не знайшов. 2 тіста виконуються в середньому однаковий час (без sleep), можуть мати різні порядки дисперсії.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.