Постановка питання
Нещодавно, під час співбесіди в одну велику компанію мені задали просте запитання, що таке Load Average. Не знаю, на скільки правильно я відповів, але особисто для себе прийшло усвідомлення, що точної відповіді я насправді і не знаю.
Більшість людей напевно знають, що Load Average - це середнє значення завантаження системи за деякий період часу (1,5 і 15 хвилин). Так само можна дізнатися деякі подробиці з даної статті. про те, як цим користуватися. У більшості випадків цих знань досить для того, що б за значенням LA оцінювати завантаження системи, але я за фахом фізик, і коли я бачу «середнє за проміжок часу» мені відразу стає цікава частота дискретизації на даному проміжку. А коли я бачу термін «очікують ресурсів», стає цікаво, які саме і скільки часу треба чекати, а так само скільки тривіальних процесів треба запустити, щоб отримати за короткий проміжок часу високий LA. І головне, чому відповіді на ці питання не дає 5 хвилин роботи з гуглом? Якщо вам дані тонкощі так само цікаві, ласкаво просимо під кат.
Щось тут не так…
Для початку визначимося з тим, що ми знаємо. У загальному вигляді Load Average це середня кількість очікують ресурсів ЦПУ процесів за один з трьох проміжків часу. Так само нам відомо, що це значення в нормальному стані знаходиться в діапазоні від 0 до 1, і одиниця відповідає 100% завантаженні одноядерной системи без перевантаження. Надалі я буду розглядати систему як одноядерний, оскільки це простіше і показово.
Що тут не так?
По перше. всі ми знаємо, що середнє арифметичне кількох величин дорівнює сумі цих величин, поділеній на їх кількість. З тієї інформації, що у нас є абсолютно незрозуміло це саме кількість. Якщо ми вважаємо очікують процеси в перебігу всієї хвилини, то середнє значення буде дорівнює кількості процесів за хвилину, поділеній на одиницю. Якщо будемо вважати кожну секунду - то і кількість процесів в кожному підрахунку зменшиться з діапазоном, і ділити будемо на 60. Таким чином ніж більша їх кількість при наборі даних, тим менше середнє значення ми отримаємо.
По друге що означає «очікує ресурсів процес»? Якщо ми запустимо велику кількість швидких процесів разом, то всі вони встануть в чергу, і за логікою на короткий проміжок часу LA повинен вирости до абсолютно неприйнятних величин, і при тривалому моніторингу повинні спостерігатися постійні скачки, чого, в нормальній ситуації, немає.
По-третє. одноядерна система при 100% завантаженні повинна давати Load Average рівний 1. Але тут немає ніякої залежності від параметрів цього ядра, хоча кількість процесів може відрізнятися в рази. Дане питання може бути знято або коректним визначенням «очікує ресурсів процесу», або наявністю якоїсь нормування на параметри ядра.
література
Трохи ядерної магії
З даних матеріалів можна дізнатися, що кожному викликається процесу дається обмежений проміжок часу на використання CPU, в стандартній архітектурі intel цей проміжок дорівнює 10мс. Це ціла сота частка секунди і в більшості випадків процесу стільки часу не потрібно. Однак, якщо якийсь процес використовував весь відведений йому час, то викликається апаратне переривання і система повертає собі управління процесором. Крім цього кожні 10мс збільшуючи лічильник тиків (jiffies counter). Дані тики вважаються з моменту запуску системи і кожні 500 тиків (раз в 5 секунд) розраховується Load Average.
Код безпосередньо розрахунку знаходиться в ядрі в файлі timer.c (код наведено для версії 2.4, у версії 2.6 все це кілька розосереджено, але логіка не змінилася, далі, сподіваюся, теж істотних змін немає, але, чесно кажучи, останні релізи не перевіряв) :
Як видно, розраховуються по черзі ті самі три значення LA, однак не вказано, що саме вважається, і як саме вважається. Це теж не проблема, код функції count_active_tasks () знаходиться в тому ж файлі, трохи вище:
А CALC_LOAD лежить в sched.h разом з декількома цікавими константами:
З усього перерахованого вище можна сказати, що раз в 5 секунд ядро дивиться, скільки всього процесів перебуває в стані RUNNING і UNINTERRUPTIBLE (до речі в інших UNIX системах це не так) і для кожного такого процесу збільшує лічильник на FIXED_1, що дорівнює 1< Ні, тут не розпадається ядро системи, просто формула CALC_LOAD, по якій вважається Load Average заснована на законі радіоактивного розпаду. або просто експоненціального затухання. Даний закон є не що інше, як рішення диференціального рівняння, тобто кожне нове значення розраховується з попереднього і швидкість зменшення кількості елементів безпосередньо залежить від кількості елементів. Фактично Load Average не є середнім значенням в звичайному розумінні середнього арифметичного. Це дискретна функція, періодично розраховується з моменту запуску системи. При цьому значення функції є кількість відпрацьовують в системі процесів в умовах експоненціального затухання. 2 ^ 11 для нас в даному випадку рівносильно одиниці, ми її зафіксували спочатку і додавали всюди, кількість нових процесів так само розраховується в цих величинах. А, де T - інтервал вимірювання (1,5 або 15 хвилин). Тепер, розуміючи, як розраховується LA можна спробувати відповісти на питання, поставлені на початку статті: Однак крім відповідей на наявні спочатку питання розбір коду ставить і нові. Наприклад, чи застосовна загасаюча експонента до скорочення числа очікують процесів? Якщо ми розглядаємо радіоактивний розпад, то його швидкість обмежена лише кількістю ядер, в нашому ж випадку, при великій кількості процесів все все упреться в пропускну здатність CPU. Так само, якщо порівняти отриману формулу з експоненціальним законом, стає видно, що, де T - тривалість інтервалу набору даних (1,5 або 15 хвилин). Таким чином розробники ядра вважають, що швидкість зменшення Load Average обернено пропорційна тривалості вимірювань, що кілька неочевидно, принаймні для мене. Ну і не складно змоделювати ситуації, коли величезні значення LA НЕ будуть реально відображати завантаження системи, або навпаки.Трохи ядерного розпаду
Рішенням даного диференціального рівняння є експонентний закон:
Таку конструкцію ми спостерігаємо, переписавши розрахункову частину CALC_LOAD математичною мовою:
Варто зауважити, що при фіксованому часовому інтервалі і фіксованому часу між вимірами значення експоненти цілком можуть бути пораховані заздалегідь і використовуватися як константа, що в коді і робиться. Остання операція - зміщення вправо на 11 біт дає нам шукане значення Load Average з відкиданням нижніх порядків.
1) Середнє значення не є середнім арифметичним, а є середнє значення функції, яка розраховується кожні 5 секунд з моменту старту системи.
2) «Очікується ресурсів CPU» вважаються всі процеси, що знаходяться в стані RUNNING і UNINTERRUPTIBLE. А істотних стрибків Load Average при тривалому моніторингу ми не спостерігаємо, оскільки загасаюча експонента грає роль згладжує функції (хоча при розгляді періоду в 1 хвилину їх можна помітити).
3) А ось тут один з найцікавіших висновків. Справа в тому, що зазначена вище функція Load Average за будь-яких значеннях n монотонно зростає до цього значення, якщо ж n
В кінцевому рахунку складається враження, що для розрахунку Load Average була обрана згладжує функція, максимально швидко зменшує своє значення, що в цілому логічно для отримання звичайно числа, але не відображає реально, що відбувається. І якщо хто-небудь мені пояснить, чому саме експонента і чому саме в такому вигляді, буду дуже вдячний.Схожі статті