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

B6. Профілювання

просунутийспирається на модуль 13, модуль 18

Остання робота курсу застосовує попередні модулі до одного практичного питання: чому це повільно? Головна навичка тут полягає в порядку дій. Профілювальник функцій показує, де програма рахує, але спершу треба з’ясувати, чи вона взагалі рахує, чи чекає на диск або на пам’ять. Шлях read() через ядро і кеш сторінок описано в модулі 13, рядки кеша і промахи в модулі 2, а трасування через eBPF у модулі 18.

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

  • за top і станом процесу сказати, чи бракує програмі процесора, чи вона чекає на ввід-вивід;
  • прочитати вивід strace -c і назвати системний виклик, у якому минає час, і скільки разів він викликається;
  • знайти гарячу функцію через perf record і perf report;
  • за IPC і cache-misses із perf stat відрізнити обчислення від очікування пам’яті;
  • показати розподіл затримок диска через biolatency або iostat -xz.

Так виглядає перша година будь-якого розбору «сервіс став повільним»: перш ніж чіпати код, треба довести числами, де втрачається час, а після виправлення виміряти ще раз.

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

Що зробити: три задачі нижче. У кожній треба знайти причину, довести її вимірюванням і виправити, а потім показати числа до і після. Ідіть за «Порядком дій»: спершу з’ясувати, чекає програма чи рахує, і лише потім брати профілювальник.

  1. Програма, що чекає.

    Візьміть або напишіть програму, яка читає файл дрібними порціями по 1 байту. Знайдіть це через strace -c, виправте буферизацією, покажіть різницю в кількості системних викликів і в часі (модуль 3).

  2. Програма, що промахується повз кеш.

    Обхід двовимірного масиву за стовпцями замість рядків. Доведіть через perf stat, що справа в роботі з пам’яттю, а не в кількості операцій: кількість інструкцій має лишитися майже тією самою (модуль 2).

    Дивіться передусім на cache-references, не лише на cache-misses: вибухає кількість звернень за межі L1. Для звірки, масив 3000×3000 (34 МіБ), однакові 127 млн інструкцій в обох випадках:

    Обхід cache-references cache-misses
    за рядками 2.0 млн 1.35 млн
    за стовпцями 35.8 млн 1.59 млн
  3. Система, що гальмує через диск.

    Створіть навантаження (fio або dd у циклі), знайдіть винуватця через iostat -xz і biolatency з bpftrace, покажіть розподіл затримок (модуль 13, модуль 14).

Чого робити не треба. Не оптимізуйте наосліп: зміна без виміру до і після не зараховується. Флейм-графи і власні програми bpftrace лишаються для розділу «Далі, якщо цікаво».

Обмеження. Для задачі 2 потрібна програма на C, зібрана з -g: інакше perf report покаже адреси замість імен функцій. Для задач 1 і 3 мова довільна.

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

  • для задачі 1: кількість системних викликів і час зі strace -c до і після буферизації;
  • для задачі 2: instructions, cache-references і cache-misses зі perf stat для обходу за рядками і за стовпцями;
  • для задачі 3: розподіл затримок із biolatency або r_await/w_await з iostat -xz і назву процесу, що створював навантаження;
  • для кожної задачі: стан процесу і %wa з top на першому кроці порядку дій і висновок, який ви з них зробили.

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

  • ви можете підтвердити командою кожне із семи тверджень таблиці «Що треба вміти підтвердити»;
  • у звіті для кожної з трьох задач названо причину і є числа до і після виправлення;
  • звіт містить чотири пункти вище.
  • Прочитайте в модулі 13 розділи «Шлях одного read()» і «Буферизація і кешування», у модулі 2 розділ «Ієрархія пам’яті», а в модулі 18 розділ «eBPF: ядро стало програмованим». Для задачі 1 згодиться розділ «Скільки це коштує» з модуля 3.
  • Vagrant-машина з архіву має linux-perf, bpftrace, fio і sysstat (iostat). На власній системі поставте те саме через setup/provision.sh: він до того ж знижує perf_event_paranoid і kptr_restrict, без чого perf і bpftrace не бачать символів ядра.
  • Скрипт biolatency входить до прикладів bpftrace. Заготовок і check.sh для цієї роботи в архіві немає: результат підтверджується таблицею тверджень і звітом.

Це головний матеріал роботи. Запам’ятайте послідовність: вона економить години.

  1. Чи це взагалі процесор?

    top: якщо процес у стані S або D, а %wa високий, то процесора вистачає і програма чекає. Профілювальник функцій тут не допоможе.

  2. На чому саме чекає?

    strace -T -c покаже, у яких системних викликах минув час. Для стану D — cat /proc/<pid>/wchan або stack: там назва функції ядра, у якій процес заснув.

  3. Якщо процесор — то де?

    perf top для живої картини, perf record + perf report для розбору. Дивитися спершу на частку, назви функцій потім.

  4. Чи це взагалі обчислення?

    perf stat: відношення інструкцій до тактів (IPC). Значення менше одиниці означає, що процесор чекає на пам’ять замість рахувати (модуль 2). Далі дивіться cache-misses і dTLB-load-misses (модуль 11).

  5. Якщо потрібне те, чого немає в готових інструментах — bpftrace.

Що треба вміти підтвердити

Section titled “Що треба вміти підтвердити”
Твердження Чим доводиться
Ви відрізняєте очікування від обчислень top %wa + стан процесу
Ви знайшли, у якому виклику час strace -c -T
Ви знайшли гарячу функцію perf report
Ви знаєте, чи процесор рахує чи чекає perf stat, IPC
Промахи кеша виміряні, а не припущені perf stat -e cache-misses
Затримки диска показані розподілом biolatency або iostat -xz
Виправлення дало ефект числа до і після для кожної задачі

Профілювання без символів. perf report показуватиме адреси замість імен. Потрібні -g при збірці й пакети з відлагоджувальними символами.

Заміри без прогріву. Перший прогін читає з диска, а наступні вже з кеша сторінок (модуль 13). Різниця в сто разів, і до вашої оптимізації вона не має жодного стосунку.

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

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

Висновок без другого виміру. «Стало швидше» без чисел до і після результатом не вважається.

Побудувати флейм-граф із perf record і подивитися, як виглядає той самий профіль у вигляді дерева викликів. Або написати власний однорядковий bpftrace, що рахує розподіл затримок конкретного системного виклику.