Thread Director: чому процесор тепер радить операційній системі

Було корисно?

Нічого так не символізує «сучасні обчислення», як робоча станція з 64 ядрами, яка гальмує під час відкриття відеодзвінка, або сервер збірки, який випадково працює вдвічі довше по вівторках. Ви дивитеся на load average: усе нормально. Ви дивитеся на навантаження CPU: усе нормально. І тим не менш хвостова затримка підстрибує, звук клацає, або база даних вирішує, що 99-й перцентиль — це стиль життя.

Якщо ви працюєте на гібридних CPU (P-ядра + E-ядра), за багатьма скаргами «раніше було передбачувано» стоїть одна тиха зміна: процесор тепер активно підказує операційній системі, де потрібно виконувати ваші потоки. Це територія Thread Director — де планування перестає бути виключно проблемою політики ОС і стає переговором між CPU і ОС.

Що змінилося: від планування ОС до намірів, які надає CPU

Десятиліттями ми вважали планування CPU проблемою ОС. Ядро бачило runnable-потоки, вимірювало, як довго вони виконувалися, застосовувало евристики справедливості й розміщувало їх на ядрах, виходячи з топології та політики. Апаратне забезпечення переважно виконувало свою роль: виконувало інструкції, генерувало переривання й надавало лічильники.

Гібридні дизайни процесорів порушили цю чітку межу. Коли не всі ядра однакові, твердження «CPU — це CPU» стає брехнею, на якій шедулер не може базуватись. Ви все ще можете планувати «чесно», але це буде дорого — спалюючи енергію на P-ядрах для фонової роботи або позбавляючи чутливі до затримки потоки ресурсів на E-ядрах. Результат виглядає як «випадкова зміна продуктивності», тому що це так і є.

Thread Director (назва Intel; концепція ширша) — це визнання очевидного процесором: він має кращу в реальному часі видимість того, що потік робить прямо зараз. Не «цей потік використав 70% CPU за 10 мс», а «цей потік інтенсивно виконує інструкції, часто промахується в кеші, містить багато гілок, використовує векторні інструкції, стоїть у стані stall або часто прокидається». CPU може безперервно класифікувати таку поведінку й надсилати підказки — hints, не команди — шедулеру ОС.

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

Цитата, яку варто тримати на думці під час дизайн-рев’ю, приписана Werner Vogels: «Усе ламається увесь час.» Якщо ви не будуєте свої припущення про планування навколо цього, ви будуєте навколо надії.

Гібридні CPU простими словами (і чому ваша ментальна модель застаріла)

Гібрид означає щонайменше два класи ядер:

  • Performance cores (P-cores): вища одноядерна продуктивність, зазвичай вищі частоти, більші механізми out-of-order, більше енергоспоживання.
  • Efficiency cores (E-cores): менші, економніші, часто відмінний пропуск на ват, але нижчий піковий одноядерний показник і іноді інші мікроархітектурні риси.

Гібрид не є новинкою в мобільному світі. Mobile SoC давно застосовують big.LITTLE. Новим є те, що гібридні рішення з’явилися широко у десктопах, ноутбуках і навіть у деяких серверних робочих навантаженнях, де люди вважали «можна прив’язати й забути». Це припущення тепер регулярно породжує інциденти.

Шедулер має вирішити: які потоки заслуговують на P-ядра, які можуть жити на E-ядрах і коли їх переміщати. Міграція має вартість: теплота кешу, стан передбачувача гілок і іноді поведінка частоти. Але й залишати потік «в неправильному районі» також дорого: затримка, пропускна здатність або час автономної роботи.

Ось де для production-систем починається «перчинка»:

  • Більшість додатків не декларують наміри. Вони не кажуть ОС «цей потік чутливий до затримки», або «це фоновий воркер», або «це робота, обмежена пропускною здатністю пам’яті, яка не виграє від P-ядр».
  • Шедулери виводять наміри з поведінки. Поведінка швидко змінюється: HTTP-воркер може бути простоювати, потім парсити TLS, потім звертатись до бази даних, потім стискати відповідь.
  • Апаратне забезпечення бачить поведінку раніше й з більшою роздільною здатністю, ніж ОС.

Thread Director існує тому, що ОС просили приймати швидкі рішення з «затуманеними окулярами».

Короткий жарт №1: Прив’язка потоків на гібридних CPU — це як забронювати столик у ресторані, не перевіривши, в якій залі кухня.

Що насправді робить Thread Director

На високому рівні Thread Director — це система телеметрії й класифікації в апаратному забезпеченні, яка:

  1. Спостерігає поведінку на рівні потоків через лічильники продуктивності й мікроархітектурні сигнали.
  2. Класифікує потоки у категорії, пов’язані з тим, «наскільки вони виграють від P-ядр» і «наскільки вони чутливі до затримки».
  3. Передає ці класифікації шедулеру ОС через визначений інтерфейс.
  4. Дозволяє ОС розміщувати потоки на відповідних ядрах з точністю краще за евристику.

Чим це не є

  • Не магічний перемикач «зробить усе швидшим». Якщо ваше навантаження обмежене пам’яттю, P-ядро може просто чекати швидше.
  • Не заміна для планування потужності. Якщо ви насичуєте систему, вона і далі буде насиченою — просто рішення будуть дорожчими.
  • Не привід припиняти вимірювання. Це причина вимірювати інакше.

Реальний операційний вплив

Найбільший вплив — це варіативність. Гібрид без хорошого планування дає неприємну варіативність: нестабільна затримка, нестабільні часи збірки, нестабільні запити. Thread Director прагне зменшити це, покращуючи рішення про розміщення в умовах швидких змін поведінки потоків.

Але він також змінює місце, де ви відлагоджуєте проблему. «Шедулер ОС тупий» перетворюється в «шедулер ОС слідує апаратним підказкам, які можуть бути неправильно застосовані до мого навантаження, налаштувань живлення, рівня віртуалізації або стратегії pinning». Граф вини винятково розширюється. Ваші рукописи з процедурами мають йти в ногу.

Факти й історія: як ми дійшли до цього

Декілька конкретних контекстних пунктів, які допомагають пояснити, чому ми тут і чому це не зникне:

  1. Асиметричні ядра — давно знайома річ у мобільному світі. Дизайни у стилі big.LITTLE нормалізували «різні ядра для різних завдань» задовго до того, як десктопи це помітили.
  2. Масштабування частоти стало нормою. DVFS перетворив «швидкість CPU» на рухому ціль, і шедулер мусив це врахувати.
  3. Turbo-поведінка зробила продуктивність непостійною між ядрами. Навіть «однакові» ядра поводяться по-різному, коли діють обмеження живлення/тепла.
  4. SMT ускладнило значення ядра. Hyper-Threading (і подібні) створили логічні CPU, що ділять ресурси виконання, що робить розміщення ще важливішим.
  5. NUMA вже вчив нас, що топологія має значення. Сервери звикли до «не всі CPU однакові» через локальність пам’яті; гібрид приносить цю думку на масові машини.
  6. Захисні міри через безпеку змінили профілі продуктивності. Мітеги на зразок speculation mitigations зробили певні патерни викликів системних викликів дорожчими, впливаючи на те, які ядра «кращі» для яких потоків.
  7. Енергія стала першочерговим обмеженням. Лаптопні та дата-центрові обмеження живлення перетворили «найшвидше» на «достатньо швидко на ват».
  8. Шедулери історично працювали на грубих тайм-слотах. ОС бачить runnable-стани й облікові тики; CPU бачить стаги і мікс інструкцій що мить.
  9. Віртуалізація і контейнери ховали топологію від додатків. Коли ви нашаровуєте гіпервізори, cgroups і pinning, огляд шедулера може бути спотворений, якщо не налаштований уважно.

Режими відмов, які ви побачите в продакшні

Thread Director — це відповідь на реальні проблеми, але він вводить новий набір режимів відмов — головним чином створених людьми з міцними переконаннями й слабкими вимірюваннями.

1) Стрибки затримки, що корелюють з «фоновою» роботою

Класичний приклад: ваша служба здебільшого простаїть, потім запускається фонова задача або стиснення логів. Раптом хвостова затримка зростає. На гібридному обладнанні це може відбуватися, коли шедулер неправильно класифікує сплески або коли ваші чутливі до затримки потоки опиняються на E-ядрах, поки P-ядра зайняті потоками на пропускну здатність.

Thread Director може допомогти, але лише якщо ОС ефективно ним користується і ваші політики не конфліктують із ним.

2) Інциденти «pinning зробив гірше»

Приманка — прив’язувати: «я просто поставлю базу даних на швидкі ядра». Але pinning на гібридному CPU часто фіксує систему в неоптимальному стані, коли навантаження змінюється. Ви також можете випадково прив’язати критичні потоки до E-ядер — бо ваше припущення «CPU 0-7» походить від іншого SKU.

3) Політика живлення підриває планування

Windows «Balanced» проти «High performance», Linux governor-и, налаштування BIOS і служби від постачальника можуть нахиляти поле. Шедулер може бути геніальним і все одно програти, якщо платформа обмежує boost P-ядра або агресивно парковує ядра.

4) Віртуалізація ховає гібридну природу

Всередині VM гостьова ОС може не бачити справжніх класів ядер. Ваш гіпервізор може розкладати vCPU на E-ядра при конкуренції. Тепер ви розбираєте затримки додатків, які насправді є «vCPU опинився на неправильному кремнії».

5) Пробіли в спостережуваності: ви не бачите, що CPU «порадив»

Багато команд мають дашборди для використання CPU, load і run queue. Менше хто може відповісти: «Які потоки розташовані на E-ядрах і чому?» Коли ви не бачите класифікації чи шаблонів розміщення, налаштування стає ворожбарством.

Швидкий план діагностики

Порядок дій, що економить час, коли хтось дзвонить: «гібридна машина повільна й поводиться дивно». Не вигадуйте на початку. Спочатку зберіть докази.

Спочатку: підтвердіть топологію й чи ОС бачить її правильно

  • Визначте типи ядер, статус SMT і нумерацію CPU.
  • Перевірте, чи навантаження випадково обмежено (cgroups, cpuset, ліміти контейнера, taskset).
  • Перевірте, чи шедулер ОС підтримує гібридну обізнаність (версія ядра, збірка ОС).

По-друге: вирішіть, чи це проблема насичення CPU або планування/розміщення

  • Подивіться на run queue pressure, context switch-и, міграції й по-CPU використання.
  • Шукайте моделі «деякі CPU завантажені, інші бездіяльні», які кричать про проблеми з affinity/cpuset.
  • Перевірте поведінку частоти: чи P-ядра піднімають частоту? чи E-ядра виконують важку роботу?

По-третє: ізолюйте симптом до класу потоків

  • Визначте топ-злочинців за CPU time і wakeups.
  • Перевірте, чи чутливі до затримки потоки опиняються на E-ядрах під час стрибків.
  • Якщо в контейнерах/VM — перевірте планування хоста й pinning, перш ніж міняти параметри додатка.

Потім: змінюйте по одному параметру

  • Прибирайте ручні прив’язки перед тим, як додавати нові.
  • Надавайте перевагу QoS / механізмам пріоритету ОС над жорсткою афінністю, якщо немає виміряної причини.
  • Якщо потрібно прив’язувати — прив’язуйте за типом ядра навмисно, а не за «номерами CPU з блогу».

Практичні завдання: команди, виводи, і рішення

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

Завдання 1: Підтвердіть гібридну топологію й нумерацію CPU

cr0x@server:~$ lscpu -e=CPU,CORE,SOCKET,NODE,ONLINE,MAXMHZ,MINMHZ
CPU CORE SOCKET NODE ONLINE MAXMHZ MINMHZ
0   0    0      0    yes    5200.0  800.0
1   0    0      0    yes    5200.0  800.0
2   1    0      0    yes    5200.0  800.0
3   1    0      0    yes    5200.0  800.0
8   8    0      0    yes    3800.0  800.0
9   8    0      0    yes    3800.0  800.0
10  9    0      0    yes    3800.0  800.0
11  9    0      0    yes    3800.0  800.0

Що це означає: Шукайте кластери CPU з різними MAXMHZ — це часто сильна підказка про P-ядра проти E-ядр (не ідеально, але корисно). Нумерація CPU може бути не згрупована акуратно.

Рішення: Побудуйте явну мапу «швидка група» проти «повільна група» для цього хоста; не припускайте, що CPU0..N — це P-ядра.

Завдання 2: Перевірте кеш і деталі топології

cr0x@server:~$ lscpu | sed -n '1,30p'
Architecture:            x86_64
CPU(s):                  24
Thread(s) per core:      2
Core(s) per socket:      16
Socket(s):               1
L1d cache:               512 KiB (16 instances)
L1i cache:               512 KiB (16 instances)
L2 cache:                20 MiB (10 instances)
L3 cache:                30 MiB (1 instance)
NUMA node(s):            1

Що це означає: Спільні кеші важливі для вартостей міграції. Якщо E-ядра ділять L2 кластер, переміщення потоку в/з цього кластера може змінити продуктивність.

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

Завдання 3: Перевірте ядро й базовий стан шедулера

cr0x@server:~$ uname -r
6.5.0-21-generic

Що це означає: Підтримка гібридного планування сильно залежить від покоління ядра й бекпортів від вендора.

Рішення: Якщо у вас старе ядро і ви женетеся за гібридними дивностями, оновлення — це не «приємність». Це перша реальна спроба виправлення.

Завдання 4: Перевірте governor і політику частоти CPU

cr0x@server:~$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
schedutil

Що це означає: schedutil пов’язує рішення про частоту з сигналами використання шедулера. Інші governor-и можуть бути агресивнішими або більш консервативними.

Рішення: Якщо ви бачите powersave на машині, чутливій до затримки, спочатку виправте політику, а не чіпайте налаштування додатка.

Завдання 5: Спостерігайте реальні частоти під навантаженням (turbostat)

cr0x@server:~$ sudo turbostat --Summary --quiet --interval 1 --num_iterations 3
Avg_MHz  Busy%  Bzy_MHz  TSC_MHz  PkgTmp  PkgWatt
  812     6.12    4172    3000      52     12.40
 1190    18.55    4388    3000      58     21.10
  945     9.80    4021    3000      55     14.80

Що це означає: Bzy_MHz — ефективна частота під навантаженням. Якщо вона ніколи не піднімається, можливо, ви обмежені живленням, термічно обмежені або неправильно налаштовані в BIOS.

Рішення: Якщо boost заблоковано, перестаньте звинувачувати планування, поки не виправите плату й термічні обмеження платформи.

Завдання 6: Виявлення дисбалансу по CPU (деякі ядра завантажені, інші бездіяльні)

cr0x@server:~$ mpstat -P ALL 1 2
Linux 6.5.0-21-generic (server)  01/10/2026  _x86_64_  (24 CPU)

12:00:01 AM  CPU   %usr %nice %sys %iowait %irq %soft %steal %idle
12:00:02 AM  all   38.1  0.0   4.2  0.1     0.0  0.3   0.0    57.3
12:00:02 AM    0   92.0  0.0   3.0  0.0     0.0  0.0   0.0     5.0
12:00:02 AM    8    6.0  0.0   1.0  0.0     0.0  0.0   0.0    93.0

Що це означає: CPU0 сильно працює, тоді як CPU8 фактично спить. Це або афінність/cpuset, або вузьке місце одного потоку.

Рішення: Якщо ви очікували паралелізму, перевірте affinity і cpusets перед тим, як змінювати код.

Завдання 7: Перевірте run queue pressure і контекстні переключення

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 1  0      0 521312  64288 882112    0    0     1     3  812 1200 12  3 85  0
 8  0      0 519040  64288 881920    0    0     0     0 1050 9800 62  6 32  0

Що це означає: Коли r підстрибує до 8 — багато runnable-потоків. Швидке зростання cs вказує на багато context switch-ів; на гібриді це часто означає міграції й контенцію.

Рішення: Якщо runnable-потоки перевищують доступну ефективну ємність CPU, припиніть гонитву за «розміщенням» і почніть шукати насичення або блокування.

Завдання 8: Подивіться міграції шедулера і поведінку балансування (perf sched)

cr0x@server:~$ sudo perf sched record -- sleep 5
[ perf sched record: Woken up 7 times to write data ]
[ perf sched record: Captured and wrote 2.113 MB perf.data (23619 samples) ]
cr0x@server:~$ sudo perf sched latency --sort=max | sed -n '1,12p'
    Task                  |   Runtime ms  | Switches | Avg delay ms | Max delay ms
  nginx:worker-01         |      310.422  |     2381 |       0.122  |       7.843
  backup:compress         |      882.001  |     1140 |       0.410  |      21.554

Що це означає: Високий max delay для чутливих до затримки потоків свідчить про затримки планування (очікування в run queue). Якщо погані затримки співпадають із задачами на пропускну здатність — маєте проблему пріоритезації й розміщення.

Рішення: Розгляньте налаштування пріоритетів/QoS або ізоляцію галасливих фонів на E-ядра замість тотального прив’язування всього важливого на P-ядра.

Завдання 9: Перевірте поточну афінність процесу/потоку

cr0x@server:~$ pidof nginx
2140
cr0x@server:~$ taskset -cp 2140
pid 2140's current affinity list: 0-7

Що це означає: Nginx обмежений CPU 0-7. Якщо 0-7 не всі P-ядра на цій системі, ви могли випадково помістити його на змішаний або повільний набір.

Рішення: Приберіть загальну афінність, якщо не доведено користь. Якщо прив’язувати — робіть це з урахуванням класів ядер.

Завдання 10: Перевірте обмеження cgroup CPU (поширено в контейнерах)

cr0x@server:~$ cat /sys/fs/cgroup/cpuset.cpus.effective
0-11
cr0x@server:~$ cat /sys/fs/cgroup/cpu.max
80000 100000

Що це означає: cpu.max натякає на квоту (80% CPU у цьому прикладі від періоду), а cpuset обмежує доступні CPU. На гібриді поняття «ефективний CPU» складніше: 4 E-ядра ≠ 4 P-ядра для затримки.

Рішення: Для SLO, чутливих до затримки, краще прив’язувати навантаження до відомих P-ядр через cpusets, а не покладатись лише на квоти.

Завдання 11: Перевірте розподіл IRQ (переривання можуть відбирати найкращі ядра)

cr0x@server:~$ cat /proc/interrupts | sed -n '1,8p'
           CPU0       CPU1       CPU2       CPU3
  24:    812340          0          0          0  IR-PCI-MSI 524288-edge  eth0-TxRx-0
  25:         0     792110          0          0  IR-PCI-MSI 524289-edge  eth0-TxRx-1

Що це означає: Якщо всі інтенсивні переривання потрапляють на CPU0 і CPU0 — P-ядро, ви можете марнувати найкраще ядро на роботу IRQ.

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

Завдання 12: Спостерігайте wakeups потоків і розміщення (top + ps)

cr0x@server:~$ top -H -p 2140 -b -n 1 | sed -n '1,20p'
top - 00:00:10 up 10 days,  2:14,  1 user,  load average: 3.12, 2.98, 2.70
Threads:  18 total,   2 running,  16 sleeping,   0 stopped,   0 zombie
%Cpu(s):  35.0 us,  4.0 sy,  0.0 ni, 61.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
   2145 www-data  20   0  125352  11420   5120 R  62.3   0.2   1:22.10 nginx: worker
   2146 www-data  20   0  125352  11420   5120 R  58.9   0.2   1:18.44 nginx: worker
cr0x@server:~$ ps -L -o pid,tid,psr,cls,rtprio,pri,ni,comm -p 2140 | sed -n '1,8p'
  PID   TID PSR CLS RTPRIO PRI  NI COMMAND
 2140  2140   0  TS      -  19   0 nginx
 2140  2145   2  TS      -  19   0 nginx
 2140  2146   3  TS      -  19   0 nginx

Що це означає: PSR показує, на якому CPU потік останнім часом виконувався. Якщо ваші воркери часто скакають між P- і E-ядрами під час стрибків затримки, це буде видно тут у часі.

Рішення: Якщо стрибки корелюють з поганою хвостовою затримкою, прагніть стабільного розміщення: усуньте конкурентні навантаження, відрегулюйте пріоритети або використайте цільові cpusets.

Завдання 13: Перевірте, чи процес обмежується (статистика cgroup CPU)

cr0x@server:~$ cat /sys/fs/cgroup/cpu.stat
usage_usec 823412341
user_usec  792112000
system_usec 31200341
nr_periods  12490
nr_throttled 340
throttled_usec 129003210

Що це означає: Якщо nr_throttled і throttled_usec ростуть під час інцидентів, ваша «проблема шедулера» фактично є проблемою квоти.

Рішення: Підвищте квоту, перемістіть навантаження або ізолюйте його на виділені ядра. Не тонко налаштовуйте Thread Director, коли фактично ви відмовляєте в CPU часі.

Завдання 14: Перевірте cpuset проти «того, що ви думали, що прив’язали» (systemd)

cr0x@server:~$ systemctl show nginx --property=AllowedCPUs --property=CPUQuota
AllowedCPUs=0-7
CPUQuota=80%

Що це означає: systemd може накладати обмеження, про які ніхто не пам’ятає. Поєднайте це з гібридною топологією — і от у вас випадкові експерименти з продуктивністю.

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

Завдання 15: Виявити блокування, яке маскується під «повільність E-ядра»

cr0x@server:~$ sudo perf top -p 2140 --stdio --delay 2 | sed -n '1,18p'
Samples: 1K of event 'cycles', 4000 Hz, Event count (approx.): 250000000
Overhead  Shared Object        Symbol
  18.22%  nginx               ngx_http_process_request_line
  11.40%  libc.so.6           __pthread_mutex_lock
   9.10%  nginx               ngx_http_upstream_get_round_robin_peer

Що це означає: Якщо багато часу йде в mutex-lock-и, переміщення потоків на P-ядра не вирішить корінну контенцію. Це може зробити проблему гучнішою.

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

Завдання 16: Перевірте прив’язку CPU шаром віртуалізації (на боці хоста)

cr0x@server:~$ virsh vcpupin appvm
VCPU: CPU Affinity
----------------------------------
0: 0-23
1: 0-23
2: 0-23
3: 0-23

Що це означає: VM може запускатись на будь-якому CPU хоста. При конкуренції вона може опинитись на E-ядрах, а гостьова ОС буде стверджувати, що все в порядку.

Рішення: Якщо VM хостить служби, чутливі до затримки, прив’язуйте vCPU до P-ядр на рівні гіпервізора, а не всередині гостя.

Короткий жарт №2: Якщо ви не можете відтворити проблему локально, не хвилюйтеся — продакшн із задоволенням відтворить її для вас о 2:00 ранку.

Три корпоративні міні-історії з передової планування

Міні-історія №1: Інцидент через неправильне припущення

Середня SaaS-компанія розгорнула нові робочі станції для розробників, які також використовувалися як ad-hoc CI-рунери. Гібридні CPU, багато RAM, «має бути швидше». За тиждень пайплайн збірки почав показувати випадкові повільні задачі: деякі завершувалися за десять хвилин, інші — за двадцять п’ять, той самий коміт, той самий образ контейнера.

Перше припущення було знайоме: «Docker краде CPU». Команда звузила квоти CPU в cgroups, щоб «зробити чесніше». Варіативність погіршилася. Часи хвостів збільшилися, і інженери почали перезапускати задачі, поки не пощастить — дороге заняття з надійності.

Справжня причина була тоншою: їхній сервіс-рунер мав systemd-юніт з AllowedCPUs=0-7, успадкований від старого гайда налаштувань. На попередніх негібридних машинах CPU 0-7 були «половина машини, достатньо добре». На новому гібридному SKU 0-7 містили змішаний набір, що суттєво віддавав перевагу повільнішим ядрам. Під час сплесків збірок шедулер робив, що міг, але сервіс уже зафенсований у неправильному пасторі.

Виправлення не було героїчним. Вони прибрали обмеження, знову виміряли, потім ввели продуману політику: фонові задачі можуть використовувати E-ядра; чутливі інтерактивні задачі — P-ядра. Постмортем інциденту не звинувачував ОС. Він звинуватив припущення про стабільність нумерації CPU між апаратними поколіннями. І з цим погодились.

Міні-історія №2: Оптимізація, що вийшла боком

Фінтех-команда керувала сервісом низької затримки з жорсткими p99-бюджетами. Вони прочитали, що «міграція потоків шкодить кешу» і вирішили прив’язати основні воркер-потоки до P-ядр. Також вони прив’язали логування й метрики «не заважати» на E-ядра. На дошці виглядало чисто.

Кілька днів p50 трохи покращився. Потім p99 почав стрибати під час відкриття ринку. Сервіс не був загалом насичений CPU. Проте найгірші запити таймаутили. Інженери додали більше прив’язок і ізоляцій. Спайки тривали. Командир інциденту описав це як «шедулер наспрягся», що не є дієвим діагнозом.

Проблема полягала в тому, що їхній сервіс мав сплесковий патерн: головний потік роздавав роботу допоміжним потокам для криптографії і стиснення. Ці помічники не були прив’язані й часто запускалися на E-ядрах через загальний тиск розміщення. Коли прив’язані P-ядра чекали на результати допоміжників, критичний шлях подовжувався. Сам акт прив’язування зменшив здатність шедулера покращувати локальну ко-локацію взаємодіючих потоків на найкращих ядрах.

Оптимізація, що вийшла боком, базувалася на вірі, що «критичні потоки — ті, які названі ‘worker’». Насправді критичний шлях включав помічників, роботу ядра і випадкові паузи GC. Виправлення — припинити мікрокерування афінністю, знову відкрити гнучкість шедулера і застосувати більш грубий, але правильний підхід: звільнити машину від шумних сусідів, коректно відрегулювати пріоритети і забезпечити доступність P-ядр, коли CPU сигналізує про потребу.

Міні-історія №3: Нудна, але правильна практика, що врятувала день

Медіакомпанія керувала флотом серверів кодування. Гібридні CPU заходили в флот поступово — саме тут змішане обладнання справді перевіряє вашу операційну зрілість. Команда мала одну політику, яка звучить нудно й тому рідкісна: кожний новий тип апаратури отримував топологічний відбиток у конфігураційному менеджменті — кількість ядер, SMT, діапазони макс. частот і протестовану мапу cpuset.

Коли прийшла нова партія, оновлення BIOS від вендора змінило поведінку живлення і трохи підправило характеристики бусту. Аварій не сталося. Але їхні канаркові дашборди помітили «варіативність wall time кодування зросла на 12% на нових вузлах». Той алерт не був про використання CPU; він був про розподіл часу завершення задач. Знову: нудна, правильна спостережуваність.

Оскільки у них був відбиток, вони швидко перевірили, що політика «черговість робіт на E-ядрах» все ще відповідала реальності. Вони запустили turbostat під час канаркових задач, підтвердили, що P-ядра не підвищували частоту як очікувалось, і відкатали BIOS-політику замість переписування налаштувань шедулера.

Найприємніше: ніхто не сперечався емоційно. Вони сперечалися про докази. Флот залишився стабільним, а постмортем інциденту зайняв одну сторінку — недооцінена розкіш.

Типові помилки: симптом → корінна причина → виправлення

Помилка 1: «Деякі ядра простіють, отже є запас»

Симптоми: Загальне використання CPU помірне, але затримка стрибає; mpstat показує нерівномірне навантаження по CPU.

Корінна причина: Афінність або cpuset-обмеження примушують «гарячі» потоки жити в піднаборі (часто включаючи E-ядра), залишаючи інші CPU невикористаними.

Виправлення: Аудитуйте taskset, systemd AllowedCPUs, cpusets контейнерів. Спочатку приберіть обмеження; повторно вводьте лише з явною мапою P/E.

Помилка 2: «Прив’язка до P-ядр завжди покращує затримку»

Симптоми: p50 покращується, p99 погіршується; продуктивність змінюється під час сплесків.

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

Виправлення: Віддавайте перевагу пріоритету/QoS замість жорсткої афінності. Якщо прив’язуєте — прив’язуйте весь співпрацюючий набір (і валідуйте perf sched latency).

Помилка 3: «Це провина Thread Director»

Симптоми: Після апаратного оновлення з’явилась «дивна планування»; команди звинувачують CPU/ОС.

Корінна причина: Політика живлення, теплові ліміти, налаштування BIOS або прошивки пригнічують буст, змушуючи P-ядра поводитися менш «P».

Виправлення: Виміряйте реальні частоти (turbostat) під репрезентативним навантаженням. Виправте обмеження платформи перед тонкою настройкою шедулера.

Помилка 4: «Всередині VM усе однакове»

Симптоми: Гостьова ОС показує стабільне використання CPU; затримка додатку скаче; конкуренція на хості корелює зі сплесками.

Корінна причина: vCPU розкладаються на E-ядра або на контенційні CPU хоста; гість не бачить гібридну топологію.

Виправлення: Прив’язуйте або пріоритетизуйте vCPU на рівні гіпервізора. Розглядайте гібрид як проблему планування на хості.

Помилка 5: «Квота в порядку, бо середній CPU низький»

Симптоми: Періодичні обриви затримки; cpu.stat показує throttling; сплески виглядають як «гикавки шедулера».

Корінна причина: Квоти cgroup обмежують сплески, особливо руйнівно для чутливих до затримки потоків.

Виправлення: Збільште квоту або приберіть її; ізолюйте шумні навантаження через cpusets; використовуйте метрики throttling як першокласні індикатори SLO.

Помилка 6: «E-ядра — лише для сміттєвої роботи»

Симптоми: Задачі на пропускну здатність страждають; система споживає багато енергії; P-ядра зайняті фоновими задачами.

Корінна причина: Політика змушує надто багато роботи на P-ядра, ігноруючи, що E-ядра можуть давати відмінний throughput/watt.

Виправлення: Розміщуйте передбачувану роботу на пропускну здатність навмисно на E-ядра, залишаючи P-ядра для сплескової/чутливої до затримки роботи. Валідуйте результат по розподілу часу завершення задач, а не за просто CPU%.

Перевірочні списки / покроковий план

Покроково: введення гібридного хоста у продакшн-фліт

  1. Інвентаризація топології: зафіксуйте модель CPU, кількість ядер, SMT, діапазони макс. частот, NUMA вузли, макет кешу.
  2. Базова підтримка ОС: підтвердіть версію ядра/збірку ОС і переконайтесь, що ви не на «версії шедулера з мого ноутбука».
  3. Встановіть політику живлення свідомо: виберіть governor/план, що відповідає класу сервісу (затримка vs пропускна здатність vs батарея).
  4. Запустіть канарки з реальним навантаженням: синтетичне CPU burn не відтворить поведінку класифікації.
  5. Виміряйте варіативність: відстежуйте p50/p95/p99 для затримки запитів або часу виконання задач; гібридні проблеми проявляються в варіативності.
  6. Перевірте throttling: квоти cgroup і теплові ліміти мають бути виміряні, а не вгадувані.
  7. Лише потім розглядайте affinity: ставте pinning як останній крок, а не перший.

Перевірочний список: перед тим як щось прив’язувати

  • Чи маєте ви перевірену мапу P-core/E-core для цього SKU хоста?
  • Чи підтвердили ви, що навантаження не обмежене квотами?
  • Чи виміряли ви міграції й затримки run queue за допомогою perf sched?
  • Чи потрапляють IRQ на ядра, які ви збираєтесь «зарезервувати»?
  • Чи зменшить pinning здатність шедулера ко-локувати співпрацюючі потоки?

Перевірочний список: якщо ви запускаєте контейнери на гібридних CPU

  • Віддавайте перевагу cpusets для критичних сервісів: виділіть відомі P-ядра для latency-sensitive pod-ів/сервісів.
  • Уникайте жорстких CPU-квот для сплескових сервісів; квоти роблять «короткі сплески» дорогими.
  • Розкривайте топологію для рішень про планування на правильному шарі (спочатку хост, потім оркестратор, потім навантаження).
  • Фіксуйте топологію на вузлі в інвентарі, щоб «CPU 0-7» не стала племінною легендою.

Поширені питання

Чи замінює Thread Director шедулер ОС?

Ні. Він надає підказки (telemetry-driven hints). ОС усе ще приймає остаточне рішення на основі політики, справедливості, пріоритетів, cgroups та обмежень.

Чому ОС не може самотужки розібратись?

Може — зрештою, приблизно. CPU бачить дрібнозернисту поведінку (стали, мікс інструкцій) швидше, ніж ОС може вивести це з обліку по тайм-слотам. Гібрид робить «зрештою» надто повільним, а «приблизно» — надто дорогим.

Чи це проблема лише Windows або Linux?

Це проблема гібридності. Різні ОС по-різному з цим працюють, але основний виклик — вибір між асиметричними ядрами при зміні поведінки потоків — є скрізь.

Чи варто відключати E-ядра на серверах?

Зазвичай ні. Вимкнення E-ядр — грубий інструмент, що міняє складність на марнований кремній. Робіть це тільки якщо маєте виміряну вимогу по латентності, яку не змогли досягти іншими розумними налаштуваннями.

Чи варто прив’язувати базу даних до P-ядр?

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

Чому збірки так сильно варіюють на гібридних машинах?

Збірки — сплескові й змішані: компіляція (CPU-інтенсивна), лінкування (часто одно-потокове вузьке місце), стиснення і I/O очікування. Якщо ключові фази потрапляють на E-ядра або обмежені квотами, wall time змінюється.

Який найшвидший знак, що це проблема квот/троттлінгу, а не Thread Director?

/sys/fs/cgroup/cpu.stat. Якщо throttled time росте під час інцидентів — у вас не «розміщення», а відмова у CPU-часі.

Як переривання пов’язані з гібридним плануванням?

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

Яка найбезпечніша стратегія за замовчуванням для змішаних навантажень?

Дайте шедулеру простір для роботи, підтримуйте розумну політику живлення, ізолюйте шумні фонові задачі (часто на E-ядра) і вимірюйте хвостову затримку та варіативність. Використовуйте афінність вибірково, а не емоційно.

Висновок: що робити наступного тижня

Thread Director — це не «перехоплення влади» CPU. Це визнання процесором, що він має кращі дані в реальному часі, ніж ОС, і пропонує їх, щоб планування на асиметричних ядрах перестало бути вгадуванням. Виграш — не тільки швидкість. Це передбачуваність — а передбачуваність тримає пейджери в тиші.

Практичні наступні кроки:

  1. Виберіть один гібридний хост і створіть його топологічний відбиток: групи ядер, стелі частот і «гарячі» точки IRQ.
  2. Додайте два дашборди: варіативність часу задач/журналу й throttling CPU. Середній CPU — брехун; розподіли — дорослі.
  3. Аудитуйте флот на предмет прихованої афінності: systemd AllowedCPUs, використання taskset, cpusets контейнерів.
  4. Коли бачите стрибки затримки, запускайте швидкий план діагностики у вказаному порядку. Не імпровізуйте.
  5. Якщо прив’язуєте — робіть це з наміром: за перевіреним класом ядра, з вимірюванням і планом відкату.

CPU тепер підказує. Вам не потрібно бездумно йому підкорятися — але припиніть робити вигляд, що він не розмовляє.

← Попередня
Міграція домену WordPress без втрати SEO: 301s, канонікали, карти сайту і нуль драм
Наступна →
Стилі друку для документації, що не бентежать

Залишити коментар