Перейти до вмісту

B2. Власний mini-top

базовийспирається на модуль 2, модуль 6

Машина гальмує, ви відкриваєте top, і перше запитання: чи вірити стовпцю %CPU. Нічого магічного top не робить: він двічі читає текстові файли з /proc і ділить різницю на час. У цій роботі ви напишете такий монітор самі й побачите те, що описують модуль 6 про стани процесу і /proc і модуль 2 про таймер, який лічить тики.

Після цієї роботи ви зможете:

  • обійти /proc і зібрати по кожному процесу назву, стан, користувача, спожитий час і RSS;
  • порахувати %CPU за різницею двох вимірів і пояснити, чому один вимір дає середнє за все життя процесу;
  • прочитати рядок cpu з /proc/stat і відрізнити «бракує процесора» від «чекаємо на диск» за iowait;
  • розібрати /proc/<pid>/stat для процесу, у назві якого є пробіл чи дужка, без зсуву полів;
  • пояснити за підсумком станів, що означає зростання D або Z.

Це та сама робота, яку роблять, коли top показує 100% на ядрі, а причина неочевидна: перевірити, звідки взялося число, скільки процесів чекають на диск і чи не накопичуються зомбі.

Написати програму minitop, яка читає /proc і показує процеси з їхнім поточним завантаженням процесора, у трьох режимах:

Terminal window
./minitop # оновлення раз на секунду
./minitop --once # один знімок і вихід, зручно для перевірки
./minitop -n 10 # десять найважчих процесів

Що має вміти:

  • обходити /proc і не падати, коли процес зникає між readdir і open;
  • показувати по кожному процесу PID, користувача, стан, %CPU, RSS і назву;
  • рахувати %CPU за різницею utime + stime між двома вимірами, у режимі --once теж: процес, який щойно вантажив процесор і заспокоївся, має показувати близьке до нуля;
  • показувати загальне завантаження з рядка cpu у /proc/stat, iowait окремо;
  • сортувати за %CPU і показувати перші N за -n;
  • підсумовувати стани: скільки процесів у R, S, D, Z;
  • розбирати назву з пробілами й дужками без зсуву полів;
  • у режимі --once завершуватися самостійно: автоперевірка чекає на знімок не більше 20 секунд.

Формат --once зафіксований, бо на нього спирається автоперевірка: один рядок заголовка, далі по рядку на процес із шістьма полями через пробіли, а наприкінці рядок підсумку за станами.

PID USER STATE CPU RSS NAME
1 root S 0.0 12484 systemd
842 michael R 99.3 3120 sh
...
states R=2 S=181 D=0 Z=1

CPU показує відсоток одного ядра, RSS подано в кілобайтах. NAME іде останнім і може містити пробіли, тому полів у рядку буває більше за шість: перші п’ять фіксовані, решта рядка є назвою. В інтерактивному режимі формат вільний: там ви робите вивід для людини.

Чого робити не треба. Потоки, дерево процесів, кольори й керування з клавіатури до цієї роботи не входять. Автоперевірка дивиться лише на вивід --once.

Обмеження. Мова будь-яка. Заборонено лише викликати top чи ps і розбирати їхній вивід: уся інформація береться з /proc.

Що записати у звіт:

  • як ви ділите %CPU: на одне ядро чи на всі, і що показують два зациклені процеси на одному ядрі;
  • значення getconf CLK_TCK на вашій системі й де воно входить у формулу;
  • скільки процесів у стані D ви побачили під важким дисковим навантаженням порівняно зі спокійною системою;
  • що сталося з першим варіантом програми, коли процес зник під час обходу, і як ви це обробили.

Готово, коли:

  • ./check.sh ./minitop проходить усі п’ятнадцять перевірок;
  • зациклений sh -c 'while :; do :; done' показує у вашому моніторі близько 100%, а той самий процес після зупинки циклу близько 0%;
  • у звіті є чотири пункти вище.
  • Прочитайте в модулі 6 розділи «Стани і переходи», «Зомбі та сироти» і «Як це насправді в Linux» (частину про /proc/self/status), а в модулі 2 розділи «Переривання і винятки» і «Як це насправді в Linux» (частину про /proc/interrupts).
  • Розпакуйте архів курсу: перевірка лежить у labs/b2-mini-top/check.sh.
  • Знадобляться getconf CLK_TCK, man 5 proc і top для звірки. Підійде будь-який Linux, зокрема контейнер і WSL2.
Що Файл Поле
Список процесів /proc числові каталоги
Назва, стан, PPID /proc/<pid>/stat 2, 3, 4
Спожитий час /proc/<pid>/stat utime (14), stime (15)
Пам’ять /proc/<pid>/status VmRSS
Користувач /proc/<pid>/status Uid → /etc/passwd
Час системи /proc/stat рядок cpu
Тиків на секунду — getconf CLK_TCK
  1. Один знімок. Обійти /proc, зібрати назви й стани, вивести таблицю.

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

  2. Завантаження процесора.

    Двічі прочитати utime + stime з інтервалом Δt і порахувати:

    %CPU = (Δ(utime + stime) / CLK_TCK) / Δt × 100

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

  3. Загальне завантаження системи.

    Те саме для рядка cpu з /proc/stat: різниця по кожному полю, частка не-idle у сумі. Стовпець iowait виведіть окремо: він відрізняє «бракує процесора» від «чекаємо на диск» (модуль 13).

  4. Сортування й оновлення. Топ-N за %CPU, оновлення раз на секунду.

  5. Підсумок за станами. Скільки процесів у R, S, D, Z. Запустіть поруч щось важке для диска й подивіться, як росте D.

Перевірка лежить в архіві з файлами курсу, і команди нижче виконуються з розпакованого каталогу.

Terminal window
cd labs/b2-mini-top
./check.sh ./minitop

Скрипт запускає навантаження з відомою поведінкою й перевіряє, що ваш монітор його бачить: знаходить процес, показує близький до очікуваного %CPU, помічає зомбі й не падає, коли процес зникає під час обходу.

Падіння на зниклому процесі. /proc/1234/stat перестає існувати між readdir і open, тож обробляйте ENOENT як звичайну ситуацію.

Назва процесу розбирається неправильно. Друге поле /proc/<pid>/stat береться в дужки й цілком може містити і пробіли, і дужки. Різати рядок пробілами не можна, шукайте останню ).

%CPU рахується за одним виміром. Тоді ви показуєте середнє за весь час життя процесу замість поточного навантаження, і воно майже завжди близьке до нуля.

Забуто CLK_TCK. Значення в /proc подано в тиках, не в секундах, і сотня тиків на секунду стандартом не гарантована.

VSZ замість RSS. Показує адресний простір, а не спожиту пам’ять (модуль 10).

Додати режим -H, який показує окремі потоки з /proc/<pid>/task, і подивитися на багатопотоковий процес (модуль 8).